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

io.vlingo.reactivestreams.StreamProcessor Maven / Gradle / Ivy

There is a newer version: 1.7.5
Show newest version
// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.reactivestreams;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.function.Consumer;

import org.reactivestreams.Processor;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import io.vlingo.actors.Actor;
import io.vlingo.actors.Stoppable;
import io.vlingo.common.Completes;
import io.vlingo.common.Scheduled;
import io.vlingo.reactivestreams.sink.ConsumerSink;

/**
 * A {@code Processor} implementation, where as a {@code Subscriber} I consume from an
 * upstream {@code Publisher}, perform an operation on those signals using {@code Operator},
 * and emit new signals via my own {@code Publisher}.
 * 

* My instances reuse {@code StreamSubscriberDelegate} and {@code StreamPublisherDelegate}. * * @param the type that the Subscriber side consumes * @param the type that the Publisher side emits */ public class StreamProcessor extends Actor implements Processor, ControlledSubscription, Scheduled, Stoppable { private final StreamPublisherDelegate publisherDelegate; private final PublisherSource publisherSource; private final long requestThreshold; private final StreamSubscriberDelegate subscriberDelegate; /** * Construct my default state with {@code transformer}, {@code requestThreshold}, and {@code configuration}. * @param operator the {@code Operator} that performs on an instance of T to yield an instance of R * @param requestThreshold the long number of signals accepted by my subscription * @param configuration the PublisherConfiguration used by my publisher */ @SuppressWarnings("unchecked") public StreamProcessor( final Operator operator, final long requestThreshold, final PublisherConfiguration configuration) { this.requestThreshold = requestThreshold; this.subscriberDelegate = new StreamSubscriberDelegate<>(new ConsumerSink<>(new ConsumerOperator(operator)), requestThreshold, logger()); this.publisherSource = new PublisherSource(); this.publisherDelegate = new StreamPublisherDelegate<>(publisherSource, configuration, selfAs(ControlledSubscription.class), scheduler(), selfAs(Scheduled.class), selfAs(Stoppable.class)); } //=================================== // Subscriber //=================================== @Override public void onSubscribe(final Subscription subscription) { // System.out.println("PROCESSOR-ONSUBSCRIBE: " + subscription); subscriberDelegate.onSubscribe(subscription); } @Override public void onNext(final T value) { // System.out.println("PROCESSOR-ONNEXT: " + value); subscriberDelegate.onNext(value); } @Override public void onComplete() { // System.out.println("PROCESSOR-ONCOMPLETE"); this.subscriberDelegate.onComplete(); publisherSource.termiante(); } @Override public void onError(final Throwable cause) { // System.out.println("PROCESSOR-ONERROR: " + cause.getMessage()); publisherDelegate.publish(cause); subscriberDelegate.onError(cause); publisherSource.termiante(); } //=================================== // Publisher //=================================== @Override public void subscribe(final Subscriber subscriber) { // System.out.println("PROCESSOR-ONSUBSCRIBE: " + subscriber); publisherDelegate.subscribe(subscriber); } //=================================== // Scheduled //=================================== @Override public void intervalSignal(Scheduled scheduled, Void data) { publisherDelegate.processNext(); } //=================================== // ControlledSubscription //=================================== @Override public void cancel(final SubscriptionController controller) { subscriberDelegate.cancelSubscription(); publisherDelegate.cancel(controller); } @Override public void request(final SubscriptionController controller, final long maximum) { publisherDelegate.request(controller, maximum); } //=================================== // Stoppable //=================================== @Override public void stop() { publisherSource.termiante(); super.stop(); } //=================================== // ConsumerTransformer //=================================== private class ConsumerOperator implements Consumer { private final Operator operator; ConsumerOperator(final Operator operator) { this.operator = operator; } @Override public void accept(final T value) { try { operator.performInto(value, (transformed) -> publisherSource.enqueue(transformed)); } catch (Exception e) { publisherDelegate.publish(e); } } } //=================================== // PublisherSource //=================================== private class PublisherSource implements Source { private boolean terminated; private final Queue values; PublisherSource() { this.values = new ArrayDeque<>(); this.terminated = false; } @Override public Completes> next() { return next((int) requestThreshold); } @Override public Completes> next(final int maximumElements) { if (values.isEmpty()) { if (subscriberDelegate.isFinalized() || terminated) { return Completes.withSuccess(Elements.terminated()); } return Completes.withSuccess(Elements.empty()); } return Completes.withSuccess(Elements.of(nextValues(maximumElements))); } @Override public Completes> next(final long index) { return next((int) requestThreshold); } @Override public Completes> next(final long index, final int maximumElements) { return next(maximumElements); } @Override public Completes isSlow() { return Completes.withSuccess(false); } void enqueue(final R value) { values.add(value); } void termiante() { terminated = true; // Terminate stops accumulating new values. Already accumulated values can be still consumed by {@link #nextValues()}. // values.clear(); } private R[] nextValues(final long maximum) { final long elements = Math.min(values.size(), maximum); @SuppressWarnings("unchecked") final R[] nextValues = (R[]) new Object[(int) elements]; for (int idx = 0; idx < nextValues.length; ++idx) { nextValues[idx] = values.poll(); } return nextValues; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy