io.baratine.stream.ResultStreamBuilder Maven / Gradle / Ivy
Show all versions of api Show documentation
/*
* Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
*
* This file is part of Baratine(TM)
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Baratine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Baratine 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Baratine; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package io.baratine.stream;
import io.baratine.function.BiConsumerSync;
import io.baratine.function.BiFunctionSync;
import io.baratine.function.BinaryOperatorSync;
import io.baratine.function.ConsumerAsync;
import io.baratine.function.ConsumerSync;
import io.baratine.function.FunctionAsync;
import io.baratine.function.FunctionSync;
import io.baratine.function.PredicateAsync;
import io.baratine.function.PredicateSync;
import io.baratine.function.SupplierSync;
import io.baratine.service.Cancel;
import io.baratine.service.Result;
import io.baratine.service.ResultStream;
import java.util.stream.Stream;
/**
* Interface {@code ResultStreamBuilder} provides access to a sequence of
* elements supplied by a remote service.
*
* It supports a set of remote and local filtering, mapping and aggregate
* operations.
*
* For service methods that produce a stream of values {@code ResultStreamBuilder}
* is used as a return type in the corresponding method declaration. e.g.
*
*
*
* public interface Graduates {
* ResultStreamBuilder<String> streamNames(int year, char nameStartsWith);
* }
*
*
*
* A service implementing {@code Graduates} interface must provide a
* distinct corresponding service method that fulfills obligation declared with
* {@code ResultStreamBuilder<String> Graduates#streamNames(int, char)}.
*
* The corresponding service method must have the same name and accept
* the same list of parameters as the declaration.
*
* In addition to the original parameters the method must accept a parameter of
* type {@code ResultStream<T>} where T is the same type as the type in the
* interface. By convention that parameter should be declared last.
*
* e.g.
*
*
*
* @io.baratine.core.Service("public://pod/graduates")
* public class GraduatesImpl implements Graduates {
* public void streamNames(int year, char nameStartsWith, ResultStream<String> stream) {
* stream.accept("John Doe");
* stream.accept("John Oliver");
*
* stream.complete();
* }
*
* @Override
* public void ResultStreamBuilder<String> streamNames(int year, char nameStartsWith) {
* throw new UnsupportedOperationException();
* }
* }
*
*
*
*
* Java implementation of the method required as part of the {@code implements}
* contract can be empty, or since it's never actually used throw an
* {@code UnsupportedOperationException}. Throwing the exception is prefered as
* as part of good practice.
*
*
*
* Client code working with a @ResultStreamBuilder can process results using
* methods provided by the interface.
*
*
*
* public class Client {
*
* @javax.inject.Inject
* @io.baratine.core.Lookup("public://pod/graduates")
* private Graduates service;
*
* public void test() {
* ResultStreamBuilder<String> builder = service.streamNames(2000, 'J');
*
* builder.forEach(s->System.out.println(s)).exec();
* }
* }
*
*
*
* Methods of the {@code ResultStreamBuilder} interface are designed to resemble
* methods provided by the Stream class of the Java SE Streams. The important difference is that
* ResultStreamBuilder works with remote services so methods will divide into
* two groups: methods which are executed remotely and methods that are executed
* by locally.
*
* Methods from remote group will execute remotely on each of the
* nodes participating in servicing a call providing {@code ResultStreamBuilder}.
*
* Methods from local group will execute locally.
*
* When invoking a remotely executed method the provided arguments are
* serialized and re-instantiated on a remote node.
*
*
* Executing mapping, filtering or reduction operation on a data-owning node will
* provide better combined performance and / or load balancing. The main reason
* for having the code execute remotely is to harness faster access to data
* located on remote nodes.
*
* Note: for description of Baratine distributed architecture see
* http://baratine.io.
*
*
* When a method from remote group needs to be executed locally
* {@code ResultStreamBuilder} needs to be adapted with a call to method
* {@code ResultStreamBuilder local()}. Call to {@code local} produces a stream
* that will run all operations locally.
*
* Methods from remote group can accept lambda expressions that will execute
* remotely, on all the nodes of a pod (see http://baratine.io/ for description
* of Baratine distributed architecture)
*
* Baratine's ability to execute code remotely lands a hand to improving performance.
*
* Whenever possible operations should take advantage of executing remotely if
* processed data resides on remote servers or if processing remotely reduces
* amount of data that travels across the network. Operations such as map, reduce
* and filter can potentially all provide performance advantages if performed
* on service nodes.
*
* When the {@code ResultStreamBuilder} is filled in with all the needed
* map, filter, collect, reduce and for each operations it is ready to
* be executed via result(...) or exec() operations.
*
* @param A type of item in resulting stream.
* @see io.baratine.service.ResultStream
*/
public interface ResultStreamBuilder
{
//
// terminals
//
/**
* Terminal that starts execution of the stream. The call is non-blocking;
* the stream will execute after the call completes.
*
* The CancelHandle can be used for subscription patterns, where cancel
* unsubscribes the stream.
*
*
*
* ResultStreamBuilder<String> stream = ...;
* stream.forEach(s -> System.out.println(s)).exec();
*
*
*
* @return a CancelHandle to cancel a stream.
*/
Cancel exec();
/**
* Terminal that chains the new stream "to" an existing stream.
*
* @param result - an instance of ResultStream to funnel the results to.
*/
void to(ResultStream super T> result);
/**
* Terminal that returns the last value of the stream.
*
* Can be used as a completion callback for streams like forEach
* that do not return values, or as a return value for streams that
* calculate a final value like collect
or reduce
.
*
* @param result instance of Result to complete with the product of
* ResultStreamBuilder.
*/
void result(Result super T> result);
// foreach
/**
* Calls method accept() of the consumer on every item in the stream.
*
* Operation is local
*
* @param consumer consumer to be called on every item in the stream
* @return an instance of a Void ResultStreamBuilder ready for execution via
* result() or exec() methods.
*/
ResultStreamBuilder forEach(ConsumerSync super T> consumer);
/**
* Calls method accept() of the consumer on every item in the stream.
*
* Operation is local
*
* @param consumer consumer to be called on every item in the stream
* @return an instance of a Void ResultStreamBuilder ready for execution via
* result() or exec() methods.
*/
ResultStreamBuilder forEach(ConsumerAsync super T> consumer);
/**
* Method {@code first()} obtains the first item from every service node
* and cancels execution of the corresponding instances of {@code ResultStream}
* on all participating nodes.
*
* @return instance of {@code ResultStreamBuilder} ready for execution via
* result() and exec() methods.
*/
ResultStreamBuilder first();
/**
* Creates an implementation of {@code ResultStreamBuilder} which ignores
* returned values.
*
* @return an instance of a Void ResultStreamBuilder ready for execution via
* result() and exec() methods.
*/
ResultStreamBuilder ignore();
/**
* Reduce with a binary function. The operation is remote by default.
*
* In the remote mode the reducing function is serialized and sent to all
* nodes for execution. Every remote node will execute the function for every
* item of their respective instance of {@code ResultStreamBuilder}
*
*
* s = t1;
* s = op(s, t2);
* s = op(s, t3);
* result = s;
*
*
*
*
*
* ResultStreamBuilder<Integer^gt; stream = ...;
*
* ResultFuture<Integer> sum = new ResultFuture<>();
* stream.reduce((a, b) -> a + b) //a) executed remotely
* .local()
* .reduce((a, b) -> a + b) //b) executed locally
* .result(sum);
*
*
*
* Operation is remote by default
*
* @param op reduce binary function which accepts two arguments and returns a
* result of the same type
* @return an instance of {@code ResultStreamBuilder} ready for execution
* via result() and exec() methods.
*/
ResultStreamBuilder reduce(BinaryOperatorSync op);
/**
* Reduce with a binary function and an initial value. The operation is remote
* by default. The binary function serialized and sent to all nodes for
* execution. It is re-instantiated on all nodes participating in the call
* and called for every item in their respective instance of
* {@code ResultStreamBuilder}
*
*
* s = init;
* s = op(s, t1);
* s = op(s, t2);
* result = s;
*
*
*
*
* ResultStreamBuilder<Integer>stream = ...;
*
* Result<Future<Integer> sum = new ResultFuture<^gt;();
* stream.reduce(0, (a, b) -> a + b) //a) executed remotely
* .local()
* .reduce(0, (a, b) -> a + b) //b) executed locally
* .result(sum);
*
*
*
* Note: in the example above reduce (a) will execute on a remote node
* while b) will execute locally. Local reduce will operate on the sub-sums
* provided by each individual node.
*
* Operation is remote by default
*
* @param init initial value
* @param op binary function
* @return an instance of ResultStreamBuilder ready for execution via
* result() or exec() method.
*/
ResultStreamBuilder reduce(T init, BinaryOperatorSync op);
/**
* Reduce with a binary function and an initial value and then combine results
* using dedicated binary function. The operation is remote by default.
*
* The accumulator binary function is serialized and sent to every participating
* node where it is re-instantiated and called for every item in their
* respective instance of {@code ResultStreamBuilder}
*
* Combiner function is executed one time for a {@code ResultStreamBuilder}
* which combines reduced values from every node.
*
*
*
*
* ResultStreamBuilder<Integer> stream = ...;
*
* ResultFuture<Integer> sum = new ResultFuture<>();
* stream.reduce(0, (a, b) -> a + b, (x, y)-> x + y)
* .result(sum);
*
*
*
*
* In the example above reduce (a + b) will execute in the context of each
* individual node. At that point the node has a chance to reduce their
* local results. Reduce (x + y) is executed once for all of the nodes to
* combine results coming from the nodes.
*
* Note: reduce (a + b) will execute on a remote node while (x + y) will
* execute locally. Local reduce will operate on the sub-sums
* provided by each individual node.
*
* Operation is remote by default
*
* @param identity initial value
* @param accumulator accumulator function
* @param combiner combining function
* @param type of the result
* @return instance of {@code ResultStreamBuilder} ready for execution
* via result() and exec() methods.
*/
ResultStreamBuilder reduce(R identity,
BiFunctionSync accumulator,
BinaryOperatorSync combiner);
/**
* Method collect will use an accumulator and combiner functions to collect
* results from nodes into a container provided by the Supplier function.
*
* This operation is remote by default. In the remote mode the {@code init}
* and {$code accum} functions will be serialized and sent to all participating
* nodes. Re-instantiated supplier function (init) will be used to obtain an
* instance of the container. Re-instantiated accumulator function will be
* called on every item in node's respective ResultStreamBuilder.
*
* The combiner will be executed once to combine results from participating
* nodes.
* e.g.
*
*
*
* ResultStreamBuilder<String> stream = ...;
*
* Result<List<String>> result = ...;
*
* stream.collect(java.util.ArrayList<String>::new,
* (l, e) -> l.add(e),
* (a, b) -> a.addAll(b))
* .result(result);
*
*
*
* @param init supplier of the container
* @param accum an accumulator function
* @param combiner combiner funcation
* @param type of the result
* @return instance of {@code ResultStreamBuilder} ready for execution
*/
ResultStreamBuilder collect(SupplierSync init,
BiConsumerSync accum,
BiConsumerSync combiner);
//
// map/filter
//
/**
* Method map produces a stream of values using provided {@code map} function.
*
* The operation is remote by default.
*
* In the remote mode the {@code map} function represented by the map
* parameter is serialized and sent to every node participating in the call.
*
* Re-instantiated map function is then called for every item in the node's
* respective {@code ResultStreamBuilder}.
*
* Operation is remote by default
*
*
* ResultStreamBuilder<String> stream = ...;
* //map stream of strings into stream of their respective lengths.
* stream.map((a) -> a.length()).forEach(i -> System.out.println(i)).exec();
*
*
*
* @param map mapping function
* @param type of the resulting stream.
* @return an instance of {@code ResultStreamBuilder} containing mapped values,
* ready for execution via result() or exec() methods.
* @see #map(FunctionAsync)
*/
ResultStreamBuilder map(FunctionSync super T,? extends R> map);
/**
* Method map produces a stream of values using provided asynchonous {@code map}
* function.
* Operation is remote by default. In the remote mode function {@code map} is
* serialized and sent to every node participating in the call.
*
* A re-instantiated {@code map} function is used to map values from node's
* respective instance of {@code ResultStreamBuilder}.
*
* Being async assumes that the function will use a provided Result<R> to
* fulfill its promise.
*
* Provided Result can be used to pass into a mapping service.
*
*
*
* ResultStreamBuilder<String> stream = ...;
* //map stream of strings into stream of their respective lengths.
*
* ResultStreamBuilder<Integer> intStream
* = stream.map((a, r) -> _mapService.map(a, r));
*
* intStream.forEach(i -> System.out.println(i)).exec();
*
* // _mapService interface should provide method with the following signature:
* // void map(String value, Result<Integer> result);
*
*
*
* @param map function that maps an item to a resulting value
* @param type of the resulting {@code ResultStreamBuilder}
* @return instance of {@code ResultStreamBuilder} containing mapped values
* ready for execution via result() or exec() methods.
* @see #map(FunctionSync)
*/
ResultStreamBuilder map(FunctionAsync super T,? extends R> map);
/**
* Sends a filter to be used for testing values passed into a corresponding
* accept method.
*
* Predicate submitted to the method is evaluated in blocking mode, which means
*
*
*
* ResultStreamBuilder<String> stream = ...;
* stream.filter(s -> s.contains("Hello"))
* .forEach(s -> System.out.println(s))
* .exec();
*
*
*
* Operation is remote by default
*
* @param test predicate to be tested
* @return an instance of {@code ResultStreamBuilder} containing filtered values,
* ready for execution via result() or exec() methods.
*/
ResultStreamBuilder filter(PredicateSync super T> test);
/**
* Sends a filter to be used for testing values passed into a corresponding
* accept method. PredicateAsync accepts a Result parameter which can be passed
* into a remote service.
*
*
* When the Predicate needs time to complete using PredicateAsync will allow
* the corresponding ResultStream accept values without delay.
*
*
*
*
*
* ResultStreamBuilder<String> stream = ...;
* Filter filter = ...;
*
* stream.filter((s, r) -> filter.test(s, r))
* .forEach(s -> System.out.println(s)).exec();
*
* //Filter provides method with signature void test(String value, Result<Boolean> result).
*
*
*
*
*
* Operation is remote by default
*
* @param test predicate to be tested
* @return an instance of {@code ResultStreamBuilder} containing filtered values,
* ready for execution via result() or exec() methods.
*/
ResultStreamBuilder filter(PredicateAsync super T> test);
//
//
//
/**
* Method {@code peek()} invokes method {@code accept()} of the consumer on
* each item in a stream and passes that item along to the next operation
* in the stream. It allows to visit every item before it's processed by the
* next operation.
*
* e.g
*
*
* ResultStreamBuilder<String> stream = ...;
* stream.peek(s -> visit(s))
* .forEach(s -> System.out.println(s))
* .exec();
*
*
*
* Operation is remote by default
*
* @param consumer
* @return instance of ResultStreamBuilder
*/
ResultStreamBuilder peek(ConsumerSync super T> consumer);
/**
* Produces an instance of a ResultStreamBuilder with local execution of
* all operations. e.g. filter, peek, map, etc.
*
* @return instance of a local ResultStreamBuilder implementation
*/
ResultStreamBuilder local();
// StreamBuilder prefetch(int prefetch);
/**
* Collects the stream's values into a java.util.Iterable
.
*
* The Iterable
may be available before the ResultStream
* completes, which means the iterator might block waiting for new data.
*/
ResultStreamBuilder> iter();
/**
* Collects the stream's values into a java.util.Stream
.
*
* The Stream
may be available before the ResultStream
* completes, which means the stream might block waiting for new data if
* a blocking method if called on the returned stream.
*
* e.g.
*
*
* public void test(Result<List<MyEntry>> result)
* {
* ResultStreamBuilder<String> stream = ...;
*
* stream.stream().result(
* result.from(s -> s.collect(Collectors.toCollection(ArrayList::new)))
* );
* }
*
*
*
* @return ResultStreamBuilder<Stream<T>> containing an instance of Stream<T>
* to be obtained using result() method.
*/
ResultStreamBuilder> stream();
/**
* Creates a custom ResultStream stage builder. Used when the built-in
* capabilities are not sufficient.
*
* The argument is a factory to build the stage, called when the stream
* is built. The function argument is the next ResultStream. The return
* is the custom ResultStream.
*
* @param factory the custom factory for buildingt he result stream.
*/
ResultStreamBuilder custom(FunctionSync,ResultStream> factory);
}