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

com.fluxtion.compiler.builder.dataflow.DataFlow Maven / Gradle / Ivy

There is a newer version: 9.3.47
Show newest version
package com.fluxtion.compiler.builder.dataflow;

import com.fluxtion.runtime.EventProcessorBuilderService;
import com.fluxtion.runtime.dataflow.FlowFunction;
import com.fluxtion.runtime.dataflow.aggregate.AggregateFlowFunction;
import com.fluxtion.runtime.dataflow.function.MergeMapFlowFunction;
import com.fluxtion.runtime.dataflow.function.NodePropertyToFlowFunction;
import com.fluxtion.runtime.dataflow.function.NodeToFlowFunction;
import com.fluxtion.runtime.dataflow.groupby.GroupByKey;
import com.fluxtion.runtime.event.Event;
import com.fluxtion.runtime.event.Signal;
import com.fluxtion.runtime.node.DefaultEventHandlerNode;
import com.fluxtion.runtime.partition.LambdaReflection;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableBiFunction;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableFunction;
import com.fluxtion.runtime.partition.LambdaReflection.SerializableSupplier;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * Helper methods for subscribing and creating an {@link FlowBuilder} from external events or internal nodes
 * in the graph.
 */
public interface DataFlow {

    /**
     * Subscribes to events of type {@literal }. Creates a handler method in the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * so that if {@link com.fluxtion.runtime.StaticEventProcessor#onEvent(Object)} is called an invocation is routed
     * to this {@link FlowFunction}
     *
     * @param classSubscription A class literal describing the subscription
     * @param                The actual type dispatched to this {@link FlowFunction} by the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribe(Class classSubscription) {
        return new FlowBuilder<>(
                EventProcessorBuilderService.service().addOrReuse(new DefaultEventHandlerNode<>(classSubscription))
        );
    }

    /**
     * Subscribes to events of type {@literal } filtering by {@link Event#filterString()}. Creates a handler method in the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * so that if {@link com.fluxtion.runtime.StaticEventProcessor#onEvent(Object)} is called an invocation is routed
     * to this {@link FlowFunction}
     *
     * @param classSubscription A class literal describing the subscription
     * @param                The actual type dispatched to this {@link FlowFunction} by the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * @param filter            The filter string to apply
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribe(Class classSubscription, String filter) {
        return new FlowBuilder<>(
                EventProcessorBuilderService.service().addOrReuse(new DefaultEventHandlerNode<>(filter, classSubscription))
        );
    }

    /**
     * Subscribes to events of type {@literal } filtering by {@link Event#filterId()}. Creates a handler method in the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * so that if {@link com.fluxtion.runtime.StaticEventProcessor#onEvent(Object)} is called an invocation is routed
     * to this {@link FlowFunction}
     *
     * @param classSubscription A class literal describing the subscription
     * @param                The actual type dispatched to this {@link FlowFunction} by the generated {@link com.fluxtion.runtime.StaticEventProcessor}
     * @param filter            The filter int to apply
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribe(Class classSubscription, int filter) {
        return new FlowBuilder<>(
                EventProcessorBuilderService.service().addOrReuse(new DefaultEventHandlerNode<>(filter, classSubscription))
        );
    }

    /**
     * Subscribes to an internal node within the processing graph and presents it as an {@link FlowBuilder}
     * for constructing stream processing logic.
     *
     * @param source The node to be wrapped and made head of this stream
     * @param     The type of the node
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribeToNode(T source) {
        return new FlowBuilder<>(new NodeToFlowFunction<>(source));
    }

    /**
     * Subscribes to a property on an internal node within the processing graph and presents it as an {@link FlowBuilder}
     * for constructing stream processing logic. The node will be created and added to the graph
     *
     * @param sourceProperty The property accessor
     * @param             The type of the node
     * @param             The type of the property that will be supplied in the stream
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribeToNodeProperty(SerializableFunction sourceProperty) {
        T source;
        if (sourceProperty.captured().length == 0) {
            try {
                source = (T) sourceProperty.getContainingClass().getDeclaredConstructor().newInstance();
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                     NoSuchMethodException e) {
                throw new RuntimeException("no default constructor found for class:"
                        + sourceProperty.getContainingClass()
                        + " either add default constructor or pass in a node instance");
            }
        } else {
            source = (T) sourceProperty.captured()[0];
        }
        return subscribeToNode(source).map(sourceProperty);
    }

    /**
     * Subscribes to a property on an internal node within the processing graph and presents it as an {@link FlowBuilder}
     * for constructing stream processing logic.
     *
     * @param propertySupplier The property accessor
     * @param               The type of the property that will be supplied in the stream
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribeToNodeProperty(SerializableSupplier propertySupplier) {
        EventProcessorBuilderService.service().addOrReuse(propertySupplier.captured()[0]);
        return new FlowBuilder<>(new NodePropertyToFlowFunction<>(propertySupplier));
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows.
     *
     * @param filterId The filter string to apply
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static FlowBuilder subscribeToSignal(String filterId) {
        return subscribe(Signal.class, filterId);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a stream that subscribes to a filtered
     * {@link Signal} event, containing an event of the type specified. Useful for invoking triggers on flows.
     *
     * @param filterId   The filter string to apply
     * @param signalType The type of value that is held by the {@link Signal} event
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribeToSignal(String filterId, Class signalType) {
        return subscribe(Signal.class, filterId).map(Signal::getValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a stream that subscribes to a filtered
     * {@link Signal} event, containing an event of the type specified. A default value is provided if the signal
     * event contains a null value. Useful for invoking triggers on flows.
     *
     * @param filterId     The filter string to apply
     * @param signalType   The type of value that is held by the {@link Signal} event
     * @param defaultValue the value to use if the signal event value is null
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder subscribeToSignal(String filterId, Class signalType, T defaultValue) {
        return subscribe(Signal.class, filterId).map(Signal::getValue).defaultValue(defaultValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a int stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows.
     *
     * @param filterId The filter string to apply
     * @return An {@link IntFlowBuilder} that can used to construct stream processing logic
     */
    static IntFlowBuilder subscribeToIntSignal(String filterId) {
        return subscribe(Signal.IntSignal.class, filterId).mapToInt(Signal.IntSignal::getValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a int stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows. A default value is provided if the signal
     * event contains a 0 value
     *
     * @param filterId     The filter string to apply
     * @param defaultValue to use if the signal event value is 0
     * @return An {@link IntFlowBuilder} that can used to construct stream processing logic
     */
    static IntFlowBuilder subscribeToIntSignal(String filterId, int defaultValue) {
        return subscribe(Signal.IntSignal.class, filterId).mapToInt(Signal.IntSignal::getValue)
                .defaultValue(defaultValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a double stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows.
     *
     * @param filterId The filter string to apply
     * @return An {@link DoubleFlowBuilder} that can used to construct stream processing logic
     */
    static DoubleFlowBuilder subscribeToDoubleSignal(String filterId) {
        return subscribe(Signal.DoubleSignal.class, filterId).mapToDouble(Signal.DoubleSignal::getValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a double stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows. A default value is provided if the signal
     * event contains a 0 value
     *
     * @param filterId     The filter string to apply
     * @param defaultValue to use if the signal event value is 0
     * @return An {@link DoubleFlowBuilder} that can used to construct stream processing logic
     */
    static DoubleFlowBuilder subscribeToDoubleSignal(String filterId, double defaultValue) {
        return subscribe(Signal.DoubleSignal.class, filterId).mapToDouble(Signal.DoubleSignal::getValue)
                .defaultValue(defaultValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a long stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows.
     *
     * @param filterId The filter string to apply
     * @return An {@link LongFlowBuilder} that can used to construct stream processing logic
     */
    static LongFlowBuilder subscribeToLongSignal(String filterId) {
        return subscribe(Signal.LongSignal.class, filterId).mapToLong(Signal.LongSignal::getValue);
    }

    /**
     * See {@link DataFlow#subscribe(Class)} shortcut method to create a long stream that subscribes to a filtered
     * {@link Signal} event. Useful for invoking triggers on flows. A default value is provided if the signal
     * event contains a 0 value
     *
     * @param filterId     The filter string to apply
     * @param defaultValue to use if the signal event value is 0
     * @return An {@link LongFlowBuilder} that can used to construct stream processing logic
     */
    static LongFlowBuilder subscribeToLongSignal(String filterId, long defaultValue) {
        return subscribe(Signal.LongSignal.class, filterId).mapToLong(Signal.LongSignal::getValue)
                .defaultValue(defaultValue);
    }


    /**
     * Merges and maps several  {@link FlowFunction}'s into a single event stream of type T
     *
     * @param builder The builder defining the merge operations
     * @param      The output type of the merged stream
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder mergeMap(MergeAndMapFlowBuilder builder) {
        MergeMapFlowFunction build = builder.build();
        return new FlowBuilder<>(build);
    }

    /**
     * Merges two {@link FlowBuilder}'s into a single event stream of type T
     *
     * @param streamAToMerge stream A to merge
     * @param streamBToMerge stream B to merge
     * @param             type of stream A
     * @param             type of stream B
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder merge(FlowBuilder streamAToMerge, FlowBuilder streamBToMerge) {
        return streamAToMerge.merge(streamBToMerge);
    }

    /**
     * Merges multiple {@link FlowBuilder}'s into a single event stream of type T
     *
     * @param streamAToMerge stream A to merge
     * @param streamBToMerge stream B to merge
     * @param streamsToMerge streams to merge
     * @param             type of stream A
     * @param             type of stream B
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    @SuppressWarnings("unchecked")
    static  FlowBuilder merge(
            FlowBuilder streamAToMerge,
            FlowBuilder streamBToMerge,
            FlowBuilder... streamsToMerge) {
        return streamAToMerge.merge(streamBToMerge, streamsToMerge);
    }

    /**
     * Applies a mapping bi function to a pair of streams, creating a stream that is the output of the function. The
     * mapping function will be invoked whenever either stream triggers a notification
     *
     * @param biFunction The mapping {@link java.util.function.BiFunction}
     * @param streamArg1 Stream providing the first argument to the mapping function
     * @param streamArg2 Stream providing the second argument to the mapping function
     * @param         The type of argument 1 stream
     * @param         The type of argument 2 stream
     * @param         The return type of the mapping function
     * @return An {@link FlowBuilder} that can used to construct stream processing logic
     */
    static  FlowBuilder mapBiFunction(SerializableBiFunction biFunction,
                                                  FlowBuilder streamArg1,
                                                  FlowBuilder streamArg2) {
        return streamArg1.mapBiFunction(biFunction, streamArg2);
    }

    static  GroupByFlowBuilder groupBy(SerializableFunction keyFunction) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupBy(keyFunction);
    }

    @SafeVarargs
    static  GroupByFlowBuilder, T> groupByFields(SerializableFunction... keyFunction) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction[0].method().getDeclaringClass();
        return subscribe(classSubscription).groupByFields(keyFunction);
    }

    static > GroupByFlowBuilder groupBy(
            SerializableFunction keyFunction, SerializableSupplier aggregateFunctionSupplier) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupBy(keyFunction, aggregateFunctionSupplier);
    }

    /**
     * Aggregates a set of instances into a multimap style structure. The key is a compound key made up from an accessor
     * of the input data
     *
     * @param keyFunction The accessor that makes up the key
     * @param          The item to aggregate
     * @return The GroupByFlowBuilder that represents the multimap
     */
    static  GroupByFlowBuilder> groupByToList(SerializableFunction keyFunction) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupByToList(keyFunction);
    }

    static  FlowBuilder> collectionFromSubscribe(Class classSubscription) {
        return subscribe(classSubscription).mapToCollection();
    }

    static  FlowBuilder> listFromSubscribe(Class classSubscription) {
        return subscribe(classSubscription).mapToList();
    }

    static  FlowBuilder> setFromSubscribe(Class classSubscription) {
        return subscribe(classSubscription).mapToSet();
    }

    /**
     * Aggregates a set of instances into a multimap style structure. The key is a compound key made up from the accessors
     * of the input data
     *
     * @param keyFunctions The accessors that make up the compound key
     * @param           The item to aggregate
     * @return The GroupByFlowBuilder that represents the multimap
     */
    @SafeVarargs
    static  GroupByFlowBuilder, List> groupByToList(LambdaReflection.SerializableFunction... keyFunctions) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunctions[0].method().getDeclaringClass();
        return subscribe(classSubscription).groupByToList(keyFunctions);
    }

    static  GroupByFlowBuilder> groupByToSet(SerializableFunction keyFunction) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupByToSet(keyFunction);
    }

    /**
     * Aggregates a set of instances into a multiset style structure. The key is a compound key made up from the accessors
     * of the input data
     *
     * @param keyFunctions The accessors that make up the compound key
     * @param           The item to aggregate
     * @return The GroupByFlowBuilder that represents the multimap
     */
    @SafeVarargs
    static  GroupByFlowBuilder, Set> groupByToSet(LambdaReflection.SerializableFunction... keyFunctions) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunctions[0].method().getDeclaringClass();
        return subscribe(classSubscription).groupByToSet(keyFunctions);
    }

    static  GroupByFlowBuilder groupBy(
            SerializableFunction keyFunction,
            SerializableFunction valueFunction) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupBy(keyFunction, valueFunction);
    }

    static > GroupByFlowBuilder
    groupBy(SerializableFunction keyFunction,
            SerializableFunction valueFunction,
            SerializableSupplier aggregateFunctionSupplier) {
        @SuppressWarnings("unchecked")
        Class classSubscription = (Class) keyFunction.method().getDeclaringClass();
        return subscribe(classSubscription).groupBy(keyFunction, valueFunction, aggregateFunctionSupplier);
    }
}