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

org.osgi.util.pushstream.PushStream Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * Copyright (c) OSGi Alliance (2015, 2018). All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osgi.util.pushstream;

import java.time.Duration;
import java.util.Collection;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.IntSupplier;
import java.util.function.LongUnaryOperator;
import java.util.function.Supplier;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collector;

import org.osgi.annotation.versioning.ProviderType;
import org.osgi.util.function.Function;
import org.osgi.util.function.Predicate;
import org.osgi.util.promise.Promise;
import org.osgi.util.promise.TimeoutException;

/**
 * A Push Stream fulfills the same role as the Java 8 stream but it reverses the
 * control direction. The Java 8 stream is pull based and this is push based. A
 * Push Stream makes it possible to build a pipeline of transformations using a
 * builder kind of model. Just like streams, it provides a number of terminating
 * methods that will actually open the channel and perform the processing until
 * the channel is closed (The source sends a Close event). The results of the
 * processing will be send to a Promise, just like any error events. A stream
 * can be used multiple times. The Push Stream represents a pipeline. Upstream
 * is in the direction of the source, downstream is in the direction of the
 * terminating method. Events are sent downstream asynchronously with no
 * guarantee for ordering or concurrency. Methods are available to provide
 * serialization of the events and splitting in background threads.
 * 
 * @param  The Payload type
 */
@ProviderType
public interface PushStream extends AutoCloseable {

	/**
	 * Close this PushStream by sending an event of type
	 * {@link PushEvent.EventType#CLOSE} downstream. Closing a PushStream is a
	 * safe operation that will not throw an Exception.
	 * 

* Calling {@code close()} on a closed PushStream has no effect. */ @Override void close(); /** * Must be run after the channel is closed. This handler will run after the * downstream methods have processed the close event and before the upstream * methods have closed. * * @param closeHandler Will be called on close * @return This stream */ PushStream onClose(Runnable closeHandler); /** * Must be run after the channel is closed. This handler will run after the * downstream methods have processed the close event and before the upstream * methods have closed. * * @param closeHandler Will be called on close * @return This stream */ PushStream onError(Consumer< ? super Throwable> closeHandler); /** * Only pass events downstream when the predicate tests true. * * @param predicate The predicate that is tested (not null) * @return Builder style (can be a new or the same object) */ PushStream filter(Predicate< ? super T> predicate); /** * Map a payload value. * * @param mapper The map function * @return Builder style (can be a new or the same object) */ PushStream map(Function< ? super T, ? extends R> mapper); /** * Asynchronously map the payload values. The mapping function returns a * Promise representing the asynchronous mapping operation. *

* The PushStream limits the number of concurrently running mapping * operations, and returns back pressure based on the number of existing * queued operations. * * @param n number of simultaneous promises to use * @param delay Nr of ms/promise that is queued back pressure * @param mapper The mapping function * @return Builder style (can be a new or the same object) * @throws IllegalArgumentException if the number of threads is < 1 or * the delay is < 0 * @throws NullPointerException if the mapper is null */ PushStream asyncMap(int n, int delay, Function< ? super T,Promise< ? extends R>> mapper); /** * Flat map the payload value (turn one event into 0..n events of * potentially another type). * * @param mapper The flat map function * @return Builder style (can be a new or the same object) */ PushStream flatMap( Function< ? super T, ? extends PushStream< ? extends R>> mapper); /** * Remove any duplicates. Notice that this can be expensive in a large * stream since it must track previous payloads. * * @return Builder style (can be a new or the same object) */ PushStream distinct(); /** * Sorted the elements, assuming that T extends Comparable. This is of * course expensive for large or infinite streams since it requires * buffering the stream until close. * * @return Builder style (can be a new or the same object) */ PushStream sorted(); /** * Sorted the elements with the given comparator. This is of course * expensive for large or infinite streams since it requires buffering the * stream until close. * * @param comparator * @return Builder style (can be a new or the same object) */ PushStream sorted(Comparator< ? super T> comparator); /** * Automatically close the channel after the maxSize number of elements is * received. * * @param maxSize Maximum number of elements has been received * @return Builder style (can be a new or the same object) */ PushStream limit(long maxSize); /** * Automatically close the channel after the given amount of time has * elapsed. * * @param maxTime The maximum time that the stream should remain open * @return Builder style (can be a new or the same object) */ PushStream limit(Duration maxTime); /** * Automatically fail the channel if no events are received for the * indicated length of time. If the timeout is reached then a failure event * containing a {@link TimeoutException} will be sent. * * @param idleTime The length of time that the stream should remain open * when no events are being received. * @return Builder style (can be a new or the same object) */ PushStream timeout(Duration idleTime); /** * Skip a number of events in the channel. * * @param n number of elements to skip * @throws IllegalArgumentException if the number of events to skip is * negative * @return Builder style (can be a new or the same object) */ PushStream skip(long n); /** * Execute the downstream events in up to n background threads. If more * requests are outstanding apply delay * nr of delayed threads back * pressure. A downstream channel that is closed or throws an exception will * cause all execution to cease and the stream to close * * @param n number of simultaneous background threads to use * @param delay Nr of ms/thread that is queued back pressure * @param e an executor to use for the background threads. * @return Builder style (can be a new or the same object) * @throws IllegalArgumentException if the number of threads is < 1 or * the delay is < 0 * @throws NullPointerException if the Executor is null */ PushStream fork(int n, int delay, Executor e); /** * Buffer the events in a queue using default values for the queue size and * other behaviors. Buffered work will be processed asynchronously in the * rest of the chain. Buffering also blocks the transmission of back * pressure to previous elements in the chain, although back pressure is * honored by the buffer. *

* Buffers are useful for "bursty" event sources which produce a number of * events close together, then none for some time. These bursts can * sometimes overwhelm downstream event consumers. Buffering will not, * however, protect downstream components from a source which produces * events faster than they can be consumed. For fast sources * {@link #filter(Predicate)} and {@link #coalesce(int, Function)} * {@link #fork(int, int, Executor)} are better choices. * * @return Builder style (can be a new or the same object) */ PushStream buffer(); /** * Build a buffer to enqueue events in a queue using custom values for the * queue size and other behaviors. Buffered work will be processed * asynchronously in the rest of the chain. Buffering also blocks the * transmission of back pressure to previous elements in the chain, although * back pressure is honored by the buffer. *

* Buffers are useful for "bursty" event sources which produce a number of * events close together, then none for some time. These bursts can * sometimes overwhelm downstream event consumers. Buffering will not, * however, protect downstream components from a source which produces * events faster than they can be consumed. For fast sources * {@link #filter(Predicate)} and {@link #coalesce(int, Function)} * {@link #fork(int, int, Executor)} are better choices. *

* Buffers are also useful as "circuit breakers" in the pipeline. If a * {@link QueuePolicyOption#FAIL} is used then a full buffer will trigger * the stream to close, preventing an event storm from reaching the client. * * @return A builder which can be used to configure the buffer for this * pipeline stage. */ >> PushStreamBuilder buildBuffer(); /** * Merge in the events from another source. The resulting channel is not * closed until this channel and the channel from the source are closed. * * @param source The source to merge in. * @return Builder style (can be a new or the same object) */ PushStream merge(PushEventSource< ? extends T> source); /** * Merge in the events from another PushStream. The resulting channel is not * closed until this channel and the channel from the source are closed. * * @param source The source to merge in. * @return Builder style (can be a new or the same object) */ PushStream merge(PushStream< ? extends T> source); /** * Split the events to different streams based on a predicate. If the * predicate is true, the event is dispatched to that channel on the same * position. All predicates are tested for every event. *

* This method differs from other methods of PushStream in three significant * ways: *

    *
  • The return value contains multiple streams.
  • *
  • This stream will only close when all of these child streams have * closed.
  • *
  • Event delivery is made to all open children that accept the event. *
  • *
* * @param predicates the predicates to test * @return streams that map to the predicates */ @SuppressWarnings("unchecked") PushStream[] split(Predicate< ? super T>... predicates); /** * Ensure that any events are delivered sequentially. That is, no * overlapping calls downstream. This can be used to turn a forked stream * (where for example a heavy conversion is done in multiple threads) back * into a sequential stream so a reduce is simple to do. * * @return Builder style (can be a new or the same object) */ PushStream sequential(); /** * Coalesces a number of events into a new type of event. The input events * are forwarded to a accumulator function. This function returns an * Optional. If the optional is present, it's value is send downstream, * otherwise it is ignored. * * @param f * @return Builder style (can be a new or the same object) */ PushStream coalesce(Function< ? super T,Optional> f); /** * Coalesces a number of events into a new type of event. A fixed number of * input events are forwarded to a accumulator function. This function * returns new event data to be forwarded on. * * @param count * @param f * @return Builder style (can be a new or the same object) */ public PushStream coalesce(int count, Function,R> f); /** * Coalesces a number of events into a new type of event. A variable number * of input events are forwarded to a accumulator function. The number of * events to be forwarded is determined by calling the count function. The * accumulator function then returns new event data to be forwarded on. * * @param count * @param f * @return Builder style (can be a new or the same object) */ public PushStream coalesce(IntSupplier count, Function,R> f); /** * Buffers a number of events over a fixed time interval and then forwards * the events to an accumulator function. This function returns new event * data to be forwarded on. Note that: *
    *
  • The collection forwarded to the accumulator function will be empty if * no events arrived during the time interval.
  • *
  • The accumulator function will be run and the forwarded event * delivered as a different task, (and therefore potentially on a different * thread) from the one that delivered the event to this {@link PushStream}. *
  • *
  • Due to the buffering and asynchronous delivery required, this method * prevents the propagation of back-pressure to earlier stages
  • *
* * @param d * @param f * @return Builder style (can be a new or the same object) */ PushStream window(Duration d, Function,R> f); /** * Buffers a number of events over a fixed time interval and then forwards * the events to an accumulator function. This function returns new event * data to be forwarded on. Note that: *
    *
  • The collection forwarded to the accumulator function will be empty if * no events arrived during the time interval.
  • *
  • The accumulator function will be run and the forwarded event * delivered by a task given to the supplied executor.
  • *
  • Due to the buffering and asynchronous delivery required, this method * prevents the propagation of back-pressure to earlier stages
  • *
* * @param d * @param executor * @param f * @return Builder style (can be a new or the same object) */ PushStream window(Duration d, Executor executor, Function,R> f); /** * Buffers a number of events over a variable time interval and then * forwards the events to an accumulator function. The length of time over * which events are buffered is determined by the time function. A maximum * number of events can also be requested, if this number of events is * reached then the accumulator will be called early. The accumulator * function returns new event data to be forwarded on. It is also given the * length of time for which the buffer accumulated data. This may be less * than the requested interval if the buffer reached the maximum number of * requested events early. Note that: *
    *
  • The collection forwarded to the accumulator function will be empty if * no events arrived during the time interval.
  • *
  • The accumulator function will be run and the forwarded event * delivered as a different task, (and therefore potentially on a different * thread) from the one that delivered the event to this {@link PushStream}. *
  • *
  • Due to the buffering and asynchronous delivery required, this method * prevents the propagation of back-pressure to earlier stages
  • *
  • If the window finishes by hitting the maximum number of events then * the remaining time in the window will be applied as back-pressure to the * previous stage, attempting to slow the producer to the expected windowing * threshold.
  • *
* * @param timeSupplier * @param maxEvents * @param f * @return Builder style (can be a new or the same object) */ PushStream window(Supplier timeSupplier, IntSupplier maxEvents, BiFunction,R> f); /** * Buffers a number of events over a variable time interval and then * forwards the events to an accumulator function. The length of time over * which events are buffered is determined by the time function. A maximum * number of events can also be requested, if this number of events is * reached then the accumulator will be called early. The accumulator * function returns new event data to be forwarded on. It is also given the * length of time for which the buffer accumulated data. This may be less * than the requested interval if the buffer reached the maximum number of * requested events early. Note that: *
    *
  • The collection forwarded to the accumulator function will be empty if * no events arrived during the time interval.
  • *
  • The accumulator function will be run and the forwarded event * delivered as a different task, (and therefore potentially on a different * thread) from the one that delivered the event to this {@link PushStream}. *
  • *
  • If the window finishes by hitting the maximum number of events then * the remaining time in the window will be applied as back-pressure to the * previous stage, attempting to slow the producer to the expected windowing * threshold.
  • *
* * @param timeSupplier * @param maxEvents * @param executor * @param f * @return Builder style (can be a new or the same object) */ PushStream window(Supplier timeSupplier, IntSupplier maxEvents, Executor executor, BiFunction,R> f); /** * Changes the back-pressure propagated by this pipeline stage. *

* The supplied function receives the back pressure returned by the next * pipeline stage and returns the back pressure that should be returned by * this stage. This function will not be called if the previous pipeline * stage returns negative back pressure. * * @param adjustment * @return Builder style (can be a new or the same object) */ PushStream adjustBackPressure(LongUnaryOperator adjustment); /** * Changes the back-pressure propagated by this pipeline stage. *

* The supplied function receives the data object passed to the next * pipeline stage and the back pressure that was returned by that stage when * accepting it. The function returns the back pressure that should be * returned by this stage. This function will not be called if the previous * pipeline stage returns negative back pressure. * * @param adjustment * @return Builder style (can be a new or the same object) */ PushStream adjustBackPressure(ToLongBiFunction adjustment); /** * Execute the action for each event received until the channel is closed. * This is a terminating method, the returned promise is resolved when the * channel closes. *

* This is a terminal operation * * @param action The action to perform * @return A promise that is resolved when the channel closes. */ Promise forEach(Consumer< ? super T> action); /** * Collect the payloads in an Object array after the channel is closed. This * is a terminating method, the returned promise is resolved when the * channel is closed. *

* This is a terminal operation * * @return A promise that is resolved with all the payloads received over * the channel */ Promise toArray(); /** * Collect the payloads in an Object array after the channel is closed. This * is a terminating method, the returned promise is resolved when the * channel is closed. The type of the array is handled by the caller using a * generator function that gets the length of the desired array. *

* This is a terminal operation * * @param generator * @return A promise that is resolved with all the payloads received over * the channel */ Promise toArray(IntFunction generator); /** * Standard reduce, see Stream. The returned promise will be resolved when * the channel closes. *

* This is a terminal operation * * @param identity The identity/begin value * @param accumulator The accumulator * @return A */ Promise reduce(T identity, BinaryOperator accumulator); /** * Standard reduce without identity, so the return is an Optional. The * returned promise will be resolved when the channel closes. *

* This is a terminal operation * * @param accumulator The accumulator * @return an Optional */ Promise> reduce(BinaryOperator accumulator); /** * Standard reduce with identity, accumulator and combiner. The returned * promise will be resolved when the channel closes. *

* This is a terminal operation * * @param identity * @param accumulator * @param combiner combines two U's into one U (for example, combine two * lists) * @return The promise */ Promise reduce(U identity, BiFunction accumulator, BinaryOperator combiner); /** * See Stream. Will resolve once the channel closes. *

* This is a terminal operation * * @param collector * @return A Promise representing the collected results */ Promise collect(Collector< ? super T,A,R> collector); /** * See Stream. Will resolve onces the channel closes. *

* This is a terminal operation * * @param comparator * @return A Promise representing the minimum value, or null if no values * are seen before the end of the stream */ Promise> min(Comparator< ? super T> comparator); /** * See Stream. Will resolve onces the channel closes. *

* This is a terminal operation * * @param comparator * @return A Promise representing the maximum value, or null if no values * are seen before the end of the stream */ Promise> max(Comparator< ? super T> comparator); /** * See Stream. Will resolve onces the channel closes. *

* This is a terminal operation * * @return A Promise representing the number of values in the stream */ Promise count(); /** * Close the channel and resolve the promise with true when the predicate * matches a payload. If the channel is closed before the predicate matches, * the promise is resolved with false. *

* This is a short circuiting terminal operation * * @param predicate * @return A Promise that will resolve when an event matches the predicate, * or the end of the stream is reached */ Promise anyMatch(Predicate< ? super T> predicate); /** * Closes the channel and resolve the promise with false when the predicate * does not matches a pay load. If the channel is closed before, the promise * is resolved with true. *

* This is a short circuiting terminal operation * * @param predicate * @return A Promise that will resolve when an event fails to match the * predicate, or the end of the stream is reached */ Promise allMatch(Predicate< ? super T> predicate); /** * Closes the channel and resolve the promise with false when the predicate * matches any pay load. If the channel is closed before, the promise is * resolved with true. *

* This is a short circuiting terminal operation * * @param predicate * @return A Promise that will resolve when an event matches the predicate, * or the end of the stream is reached */ Promise noneMatch(Predicate< ? super T> predicate); /** * Close the channel and resolve the promise with the first element. If the * channel is closed before, the Optional will have no value. * * @return a promise */ Promise> findFirst(); /** * Close the channel and resolve the promise with the first element. If the * channel is closed before, the Optional will have no value. *

* This is a terminal operation * * @return a promise */ Promise> findAny(); /** * Pass on each event to another consumer until the stream is closed. *

* This is a terminal operation * * @param action * @return a promise */ Promise forEachEvent(PushEventConsumer< ? super T> action); }