All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kolibrifx.plovercrest.server.streams.folds.CombineLatestFoldSetup Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2017, KolibriFX AS. Licensed under the Apache License, version 2.0.
 */

package com.kolibrifx.plovercrest.server.streams.folds;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.kolibrifx.lancebill.folds.CombineLatestFold;
import com.kolibrifx.plovercrest.server.internal.folds.FoldCallback;
import com.kolibrifx.plovercrest.server.internal.folds.FoldReaderInputs;
import com.kolibrifx.plovercrest.server.internal.folds.FoldReaderSetup;
import com.kolibrifx.plovercrest.server.internal.folds.FoldWriter;
import com.kolibrifx.plovercrest.server.streams.Stream;

public class CombineLatestFoldSetup implements FoldSetup {
    private final CombineLatestFold fold;

    public CombineLatestFoldSetup(final CombineLatestFold fold) {
        this.fold = fold;
    }

    @Override
    public FoldReaderSetup setupReader(final long timestamp, final FoldWriter foldOutput,
                                          final List> inputStreams) {
        final List latestValues = new ArrayList<>();
        final Map tableIndexes = new HashMap<>();
        int i = 0;
        for (final Stream s : inputStreams) {
            latestValues.add(null);
            tableIndexes.put(s.getName(), i++);
        }
        final FoldCallback foldCallback = new FoldCallback() {
            private long latestTimestamp = Long.MIN_VALUE;

            @Override
            public void onNext(final String tableName, final long timestamp, final U element) {
                final int index = tableIndexes.get(tableName);
                latestValues.set(index, element);
                if (latestValues.contains(null)) {
                    // not all values are set yet, don't invoke fold
                    return;
                }
                latestTimestamp = Math.max(timestamp, latestTimestamp);
                final T output = fold.apply(latestTimestamp, latestValues);
                if (output != null) {
                    // note: assuming that the timestamp of the output is the same as the latest input. safe?
                    foldOutput.write(timestamp, output);
                }
            }
        };
        final FoldReaderInputs inputs = new FoldReaderInputs<>();
        inputs.addInputs(inputStreams, timestamp);

        return new FoldReaderSetup() {
            @Override
            public FoldCallback getFoldCallback() {
                return foldCallback;
            }

            @Override
            public FoldReaderInputs getInputs() {
                return inputs;
            }
        };
    }

    @Override
    public long getLastOutputTimestamp(final List> inputStreams,
                                       final CombinatorStrategy combinatorStrategy) {
        // The instanceof checks are not elegant, should use some nicer multiple dispatch pattern...
        if (combinatorStrategy instanceof HistoricalCombinatorStrategy) {
            // Return the minimum of all input last timestamps
            long result = Long.MAX_VALUE;
            for (final Stream input : inputStreams) {
                final long tmp = input.getLastTimestamp();
                if (tmp == -1) {
                    // empty input
                    return -1;
                }
                result = Math.min(result, tmp);
            }
            return result;
        } else if (combinatorStrategy instanceof LiveCombinatorStrategy) {
            // Return the maximum of all input last timestamps
            long result = Long.MIN_VALUE;
            for (final Stream input : inputStreams) {
                final long tmp = input.getLastTimestamp();
                if (tmp == -1) {
                    // empty input
                    return -1;
                }
                result = Math.max(result, tmp);
            }
            return result;
        } else {
            throw new IllegalStateException("Unknown combinator strategy " + combinatorStrategy);
        }
    }
}