/* * Copyright (C) 2015 SoftIndex LLC. * * 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 io.datakernel.stream; import io.datakernel.eventloop.Eventloop; import java.util.ArrayList; import java.util.List; import static java.lang.System.arraycopy; import static java.util.Collections.unmodifiableList; /** * Represents a {@link AbstractStreamConsumer} with several {@link AbstractStreamProducer} . * * @param <I> type of receiving items */ @SuppressWarnings("unchecked") public abstract class AbstractStreamTransformer_1_N<I> implements HasInput<I>, HasOutputs { protected final Eventloop eventloop; protected AbstractInputConsumer inputConsumer; protected final List<AbstractOutputProducer<?>> outputProducers = new ArrayList<>(); private int suspendedProducersCount; protected abstract class AbstractInputConsumer extends AbstractStreamConsumer<I> { protected StreamDataReceiver<?>[] dataReceivers = new StreamDataReceiver[0]; public AbstractInputConsumer() { super(AbstractStreamTransformer_1_N.this.eventloop); } @Override protected final void onStarted() { onUpstreamStarted(); } protected void onUpstreamStarted() { } @Override protected final void onEndOfStream() { onUpstreamEndOfStream(); } protected abstract void onUpstreamEndOfStream(); @Override protected void onError(Exception e) { for (AbstractOutputProducer<?> downstreamProducer : outputProducers) { downstreamProducer.closeWithError(e); } } } protected abstract class AbstractOutputProducer<O> extends AbstractStreamProducer<O> { protected int index; public AbstractOutputProducer() { super(AbstractStreamTransformer_1_N.this.eventloop); } @Override protected final void onError(Exception e) { for (AbstractOutputProducer<?> downstreamProducer : outputProducers) { if (downstreamProducer != this) { downstreamProducer.closeWithError(e); } } inputConsumer.closeWithError(e); } @Override protected final void onDataReceiverChanged() { inputConsumer.dataReceivers[index] = downstreamDataReceiver; } @Override protected final void onSuspended() { suspendedProducersCount++; onDownstreamSuspended(); } protected abstract void onDownstreamSuspended(); @Override protected final void onResumed() { suspendedProducersCount--; onDownstreamResumed(); } protected abstract void onDownstreamResumed(); } /** * Creates a new instance of this object * * @param eventloop event loop in which this consumer will run */ public AbstractStreamTransformer_1_N(Eventloop eventloop) { this.eventloop = eventloop; } protected void setInputConsumer(AbstractInputConsumer inputConsumer) { this.inputConsumer = inputConsumer; } protected <T> StreamProducer<T> addOutput(final AbstractOutputProducer<T> downstreamProducer) { StreamDataReceiver<?>[] oldDataReceivers = inputConsumer.dataReceivers; StreamDataReceiver<?>[] newDataReceivers = new StreamDataReceiver[oldDataReceivers.length + 1]; arraycopy(oldDataReceivers, 0, newDataReceivers, 0, oldDataReceivers.length); inputConsumer.dataReceivers = newDataReceivers; downstreamProducer.index = outputProducers.size(); outputProducers.add(downstreamProducer); return downstreamProducer; } /** * Checks if all producers of this consumer are ready * * @return true if all are ready, false else */ protected boolean allOutputsResumed() { return suspendedProducersCount == 0; } protected void sendEndOfStreamToDownstreams() { for (AbstractOutputProducer<?> downstreamProducer : outputProducers) { downstreamProducer.sendEndOfStream(); } } protected void closeWithError(Exception e) { inputConsumer.closeWithError(e); for (AbstractOutputProducer<?> downstreamProducer : outputProducers) { downstreamProducer.closeWithError(e); } } public StreamConsumer<I> getInput() { return inputConsumer; } @Override public List<? extends StreamProducer<?>> getOutputs() { return unmodifiableList(outputProducers); } @Override public StreamProducer<?> getOutput(int index) { return outputProducers.get(index); } }