com.fluxtion.ext.streaming.api.Wrapper Maven / Gradle / Ivy
/*
* Copyright (C) 2018 V12 Technology Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* .
*/
package com.fluxtion.ext.streaming.api;
import com.fluxtion.api.SepContext;
import com.fluxtion.api.partition.LambdaReflection.SerializableBiFunction;
import com.fluxtion.api.partition.LambdaReflection.SerializableConsumer;
import com.fluxtion.api.partition.LambdaReflection.SerializableFunction;
import com.fluxtion.ext.streaming.api.group.GroupBy;
import com.fluxtion.ext.streaming.api.numeric.NumericFunctionStateless;
import com.fluxtion.ext.streaming.api.stream.Argument;
import static com.fluxtion.ext.streaming.api.stream.Argument.arg;
import com.fluxtion.ext.streaming.api.stream.StreamFunctions;
import com.fluxtion.ext.streaming.api.stream.StreamOperator;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
/**
* A wrapper class that holds a reference to a node in the SEP. Any node in SEP
* can be a source of a stream of values.
* Stream operations are provided to filter and map the underlying wrapped type.
*
* @author Greg Higgins
* @param
*/
public interface Wrapper {
/**
* The wrapped node
*
* @return the wrapped node
*/
T event();
/**
* The type of the wrapped node
*
* @return wrapped node class
*/
Class eventClass();
default FilterWrapper filter(SerializableFunction filter) {
return StreamOperator.service().filter(filter, this, true);
}
default FilterWrapper filter(SerializableFunction supplier, SerializableFunction extends S, Boolean> filter) {
return StreamOperator.service().filter(filter, this, supplier.method(), true);
}
default Wrapper get(SerializableFunction supplier) {
if(supplier.method().getReturnType().isPrimitive()){
return (Wrapper) map((SerializableFunction)StreamFunctions.toDouble(), supplier);
}
else{
return (Wrapper) map((SerializableFunction)StreamFunctions.toReference(), supplier);
}
}
default GroupBy group(
SerializableFunction supplier,
Class functionClass){
return StreamOperator.service().group(this, supplier, functionClass);
}
default GroupBy group(
SerializableFunction key,
SerializableFunction supplier,
Class functionClass){
return StreamOperator.service().group(this, key, supplier, functionClass);
}
/**
* Maps a value using the provided mapping function. The input is the wrapped
* instance inside this {@link Wrapper}.
* @param The return type of the mapping function
* @param mapper the mapping function
* @return A wrapped value containing the result of the mapping operation
*/
default Wrapper map(SerializableFunction mapper) {
return (Wrapper) StreamOperator.service().map((SerializableFunction) mapper, this, true);
}
/**
* Maps a value using the provided mapping function. The input is the return
* value of the supplier function invoked on the wrapped instance.
* @param The return type of the mapping function
* @param The input type required by the mapping function
* @param mapper the mapping function
* @param supplier
* @return A wrapped value containing the result of the mapping operation
*/
default Wrapper map(SerializableFunction extends S, R> mapper, SerializableFunction supplier) {
return (Wrapper) StreamOperator.service().map((SerializableFunction) mapper, this, supplier.method(), true);
}
/**
* maps a two arguments using a binary function.
* @param
* @param
* @param
* @param mapper
* @param arg1
* @param arg2
* @return
*/
default Wrapper map(SerializableBiFunction mapper, Argument arg1, Argument arg2) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg1, arg2);
}
default Wrapper map(SerializableBiFunction extends U, ? extends S, R> mapper,
SerializableFunction supplier1, SerializableFunction supplier2) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(this, supplier1), arg(this, supplier2));
}
default Wrapper map(SerializableBiFunction extends U, ? extends S, R> mapper, SerializableFunction supplier, Argument arg) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(this, supplier), arg);
}
default Wrapper map(SerializableBiFunction extends U, ? extends S, R> mapper, Argument arg, SerializableFunction supplier) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg, arg(this, supplier));
}
default Wrapper map(SerializableBiFunction extends U, S, R> mapper, SerializableFunction supplier, double arg) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(this, supplier), arg(arg));
}
default Wrapper map(SerializableBiFunction extends U, ? extends S, R> mapper, double arg, SerializableFunction supplier) {
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(arg), arg(this, supplier));
}
/**
* Maps a binary function using the wrapped instance as the first argument
* to the binary function.
*
* @param The result type of the mapping function
* @param The type of the supplied argument
* @param The input type for first argument to mapping function
* @param The input type for second argument to mapping function
* @param mapper The mapping function
* @param arg1 The second argument of the binary mapping function
* @return
*/
default Wrapper map(SerializableBiFunction mapper, Argument arg1){
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(this), arg1);
}
default Wrapper map(SerializableBiFunction mapper, double arg1){
return (Wrapper) StreamOperator.service().map((SerializableBiFunction) mapper, arg(this), arg(arg1));
}
/**
* pushes a data item from the current node in the stream to any node.The
* target node will become part of the same execution graph as the
* source.
* The returned node is the current node in the stream.
*
* @param
* @param
* @param supplier
* @param mapper
* @return the com.fluxtion.ext.declarative.api.Wrapper
*/
default Wrapper push(SerializableFunction supplier, SerializableConsumer mapper) {
StreamOperator.service().push(this, supplier.method(), mapper);
return (Wrapper) this;
}
default Wrapper push(SerializableConsumer mapper) {
StreamOperator.service().push(this, null, mapper);
return (Wrapper) this;
}
/**
* Registers a {@link Consumer} to operate on the current node when an event
* wave is passing through this node. The consumer can perform any operation
* on the node including mutations. This node, possibly mutated, is passed
* as a reference to child nodes. No new nodes are created in the stream as
* a side-effect of this processing.
*
* @param consumer {@link Consumer} of this node
* @return The current node
*/
default Wrapper forEach(SerializableConsumer consumer) {
return (Wrapper) StreamOperator.service().forEach(consumer, this, null);
}
default Wrapper forEach(SerializableConsumer consumer, String consumerId) {
return (Wrapper) StreamOperator.service().forEach(consumer, this, consumerId);
}
LongAdder counter = new LongAdder();
/**
* dump this node to console, prefixed with the supplied message.{@link Object#toString()} will be invoked on the node instance.
*
* @param
* @param prefix String prefix for the console message
* @param supplier
* @return The current node
*/
default Wrapper console(String prefix, SerializableFunction... supplier) {
StreamOperator.ConsoleLog consoleLog = new StreamOperator.ConsoleLog(this, prefix);
counter.increment();
if(supplier.length == 0 && Number.class.isAssignableFrom(eventClass())){
consoleLog.suppliers(Number::doubleValue);
}else{
consoleLog.suppliers(supplier);
}
String consoleId = "consoleMsg_" + counter.intValue();
SepContext.service().add(consoleLog, consoleId);
return this;
}
/**
* Attaches a reset notifier instance to the current stream node. If the
* node is {@link Stateful} it may be desirable to reset its state under
* controlled conditions. When the resetNotifier is on an execution path it
* will invoke the reset method of this node if it is {@link Stateful}
*
* @param resetNotifier external notifier
* @return
*/
default Wrapper resetNotifier(Object resetNotifier) {
return this;
}
/**
* Attaches an event notification instance to the current stream node. When
* the notifier updates all the child nodes of this stream node will be on
* the execution path and invoked following normal SEP rules.
*
* The existing execution path will be unaltered if either the parent
* wrapped
* node or the eventNotifier updates then the execution path will progress.
*
* @param eventNotifier external event notifier
* @return
*/
default Wrapper notiferMerge(Object eventNotifier) {
return StreamOperator.service().notiferMerge(this, eventNotifier);
}
/**
* Attaches an event notification instance to the current stream node,
* overriding the execution path of the current stream. Only when
* the notifier updates will the child nodes of this stream node be on
* the execution path.
*
* @param eventNotifier external event notifier
* @return
*/
default Wrapper notifierOverride(Object eventNotifier) {
return StreamOperator.service().notifierOverride(this, eventNotifier);
}
/**
* resets the stateful node and publishes the current value. The reset is
* after
* the last child on the execution path is executed, equivalent to {@link #immediateReset(boolean)
* }
* with value of false.
*
* @param notifier
* @return
*/
default Wrapper publishAndReset(Object notifier) {
resetNotifier(notifier);
immediateReset(false);
return notifierOverride(notifier);
}
/**
* Controls the notification policy of event notification to child nodes for
* this stream node. The default policy is to invoke child nodes when the
* return of the parent event method is true. NotifyOnChange notifies the
* child only when the parent node return of the previous cycle is false and
* this one is true.
*
*
* This can be useful if a single notification of a breach is required and
* subsequent continued breaches are swallowed, for example this can prevent
* logging spamming when combined with filters.
*
* @param notifyOnChange false = notify always. true = notify on change only
* @return The current node
*/
default Wrapper notifyOnChange(boolean notifyOnChange) {
return this;
}
/**
* Controls reset timing policy for stateful nodes. Stateful nodes are
* reset with {@link #resetNotifier(java.lang.Object)
* } or {@link #alwaysReset(boolean) }. The timing policy has the following
* behaviour:
*
* - true - the stateful node will be reset before any child nodes are
* invoked on the execution path
*
- false: - the stateful node will be reset after the final node on the
* execution path
*
*
* @param immediateReset reset timing policy
* @return
*/
default Wrapper immediateReset(boolean immediateReset) {
return this;
}
/**
* Reset a stateful node after every execution cycle, without the need for a
* an external {@link #resetNotifier(java.lang.Object) }.
*
* - true - the stateful node will be reset after every execution cycle
*
- false: - the stateful node will only be reset with {@link #resetNotifier(java.lang.Object)
* }
*
*
* @param alwaysReset - reset policy for stateful nodes
* @return
*/
default Wrapper alwaysReset(boolean alwaysReset) {
return this;
}
/**
* Set the node id for this node within the generated SEP. This is the
* variable name of the node in a Java SEP. The id must be unique for the
* SEP.
*
* @param id the unique id of the node in the SEP
* @return The current node
*/
default Wrapper id(String id) {
return StreamOperator.service().nodeId(this, id);
}
}