/** * @param collector to perform aggregation / reduction operation on the results from active stage * (e.g. to Collect into a List or String) * @param fn Function that receives the results of all currently active tasks as input * @return A new builder object that can be used to define the next stage in the dataflow */ @SuppressWarnings({"unchecked", "rawtypes"}) default <T, R> SimpleReactStream<R> allOf(final Collector collector, final Function<T, R> fn) { CompletableFuture[] array = lastActiveArray(getLastActive()); CompletableFuture cf = CompletableFuture.allOf(array); Function<Exception, T> f = (Exception e) -> { BlockingStreamHelper.capture(e, getErrorHandler()); return BlockingStreamHelper.block( this, Collectors.toList(), new StreamWrapper(Stream.of(array), true)); }; CompletableFuture onFail = cf.exceptionally(f); CompletableFuture onSuccess = onFail.thenApplyAsync( (result) -> { return new StageWithResults(this.getTaskExecutor(), null, result) .submit( () -> (R) fn.apply( BlockingStreamHelper.aggregateResults( collector, Stream.of(array).collect(Collectors.toList()), getErrorHandler()))); }, getTaskExecutor()); return (SimpleReactStream<R>) withLastActive(new StreamWrapper(onSuccess, isEager())); }
default void runThread(Runnable r) { Function<FastFuture, U> safeJoin = (FastFuture cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); new Thread( () -> new Runner(r).run(getLastActive(), new EmptyCollector(getMaxActive(), safeJoin))) .start(); }
default U reduce(U identity, BinaryOperator<U> accumulator) { if (getLastActive().isSequential()) { Object[] result = {identity}; forEach( r -> { if (result[0] == null) result[0] = r; else { result[0] = accumulator.apply((U) result[0], r); } }); return (U) result[0]; } Function<FastFuture, U> safeJoin = (FastFuture cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); IncrementalReducer<U> collector = new IncrementalReducer( this.getLazyCollector().get().withResults(new ArrayList<>()), this, getParallelReduction()); Object[] result = {identity}; try { this.getLastActive() .injectFutures() .forEach( next -> { collector.getConsumer().accept(next); result[0] = collector.reduce(safeJoin, (U) result[0], accumulator); }); } catch (SimpleReactProcessingException e) { } return collector.reduceResults( collector.getConsumer().getAllResults(), safeJoin, (U) result[0], accumulator); }
/** * Trigger a lazy stream and return the results in the Collection created by the collector * * @param collector Supplier that creates a collection to store results in * @return Collection of results */ default <A, R> R run(Collector<U, A, R> collector) { if (getLastActive().isSequential()) { // if single threaded we can simply push from each Future into the collection to be returned if (collector.supplier().get() == null) { forEach(r -> {}); return null; } A col = collector.supplier().get(); forEach(r -> collector.accumulator().accept(col, r)); return collector.finisher().apply(col); } Function<FastFuture<U>, U> safeJoin = (FastFuture<U> cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); LazyResultConsumer<U> batcher = collector.supplier().get() != null ? getLazyCollector().get().withResults(new ArrayList<>()) : new EmptyCollector<>(this.getMaxActive(), safeJoin); try { this.getLastActive() .injectFutures() .forEach( n -> { batcher.accept(n); }); } catch (SimpleReactProcessingException e) { } if (collector.supplier().get() == null) { batcher.block(safeJoin); return null; } return (R) batcher .getAllResults() .stream() .map(cf -> BlockingStreamHelper.getSafe(cf, getErrorHandler())) .filter(v -> v != MissingValue.MISSING_VALUE) .collect((Collector) collector); }
default Optional<U> reduce(BinaryOperator<U> accumulator) { if (getLastActive().isSequential()) { Object[] result = {null}; forEach( r -> { if (result[0] == null) result[0] = r; else { result[0] = accumulator.apply((U) result[0], r); } }); return (Optional) Optional.ofNullable(result[0]); } Function<FastFuture, U> safeJoin = (FastFuture cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); IncrementalReducer<U> collector = new IncrementalReducer( this.getLazyCollector().get().withResults(new ArrayList<>()), this, getParallelReduction()); Optional[] result = {Optional.empty()}; try { this.getLastActive() .injectFutures() .forEach( next -> { collector.getConsumer().accept(next); if (!result[0].isPresent()) result[0] = collector.reduce(safeJoin, accumulator); else result[0] = result[0].map(v -> collector.reduce(safeJoin, (U) v, accumulator)); }); } catch (SimpleReactProcessingException e) { } if (result[0].isPresent()) return result[0].map( v -> collector.reduceResults( collector.getConsumer().getAllResults(), safeJoin, (U) v, accumulator)); return collector.reduceResults(collector.getConsumer().getAllResults(), safeJoin, accumulator); }
default void forEach(Consumer<? super U> c) { Function<FastFuture<U>, U> safeJoin = (FastFuture<U> cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); if (getLastActive().isSequential()) { // if single threaded we can simply push from each Future into the collection to be returned try { this.getLastActive() .operation(f -> f.peek(c)) .injectFutures() .forEach( next -> { safeJoin.apply(next); }); } catch (SimpleReactProcessingException e) { } return; } IncrementalReducer<U> collector = new IncrementalReducer( this.getLazyCollector().get().withResults(new ArrayList<>()), this, getParallelReduction()); try { this.getLastActive() .operation(f -> f.peek(c)) .injectFutures() .forEach( next -> { collector.getConsumer().accept(next); }); } catch (SimpleReactProcessingException e) { } collector.getConsumer().block(safeJoin); }
default Continuation runContinuation(Runnable r) { Function<FastFuture, U> safeJoin = (FastFuture cf) -> (U) BlockingStreamHelper.getSafe(cf, getErrorHandler()); return new Runner(r) .runContinuations(getLastActive(), new EmptyCollector(getMaxActive(), safeJoin)); }