io.datakernel.datastream.processor.StreamLateBinder Maven / Gradle / Ivy
package io.datakernel.datastream.processor;
import io.datakernel.datastream.*;
import io.datakernel.promise.Promise;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import static io.datakernel.datastream.StreamCapability.LATE_BINDING;
/**
* If stream consumer is not immediately wired, on next eventloop cycle it will error out.
* This is because consumers request suppliers to start producing items on the next cycle after they're wired.
*
* This transformer solves that by storing a data receiver from consumer produce request if it is not wired
* and when it is actually wired request his new supplier to produce into that stored receiver.
*/
public final class StreamLateBinder implements StreamTransformer {
private final AbstractStreamConsumer input = new Input();
private final AbstractStreamSupplier output = new Output();
@Nullable
private StreamDataAcceptor waitingAcceptor;
// region creators
private StreamLateBinder() {
}
public static StreamLateBinder create() {
return new StreamLateBinder<>();
}
// endregion
private class Input extends AbstractStreamConsumer {
@Override
protected void onStarted() {
if (waitingAcceptor != null) {
getSupplier().resume(waitingAcceptor);
waitingAcceptor = null;
}
}
@Override
protected Promise onEndOfStream() {
return output.sendEndOfStream();
}
@Override
protected void onError(Throwable e) {
output.close(e);
}
@Override
public Set getCapabilities() {
return addCapabilities(output.getConsumer(), LATE_BINDING);
}
}
private class Output extends AbstractStreamSupplier {
@Override
protected void onProduce(StreamDataAcceptor dataAcceptor) {
StreamSupplier supplier = input.getSupplier();
if (supplier == null) {
waitingAcceptor = dataAcceptor;
return;
}
supplier.resume(dataAcceptor);
}
@Override
protected void onSuspended() {
StreamSupplier supplier = input.getSupplier();
if (supplier == null) {
waitingAcceptor = null;
return;
}
supplier.suspend();
}
@Override
protected void onError(Throwable e) {
input.close(e);
}
@Override
public Set getCapabilities() {
return addCapabilities(input.getSupplier(), LATE_BINDING);
}
}
@Override
public StreamConsumer getInput() {
return input;
}
@Override
public StreamSupplier getOutput() {
return output;
}
}