io.smallrye.mutiny.vertx.ReadStreamSubscriber Maven / Gradle / Ivy
package io.smallrye.mutiny.vertx;
import java.util.ArrayDeque;
import java.util.function.Function;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import io.vertx.core.Handler;
import io.vertx.core.streams.ReadStream;
public class ReadStreamSubscriber implements Subscriber, ReadStream {
private static final Runnable NOOP_ACTION = () -> {
};
private static final Throwable DONE_SENTINEL = new Throwable();
public static final int BUFFER_SIZE = 16;
public static ReadStream asReadStream(Publisher multi, Function adapter) {
ReadStreamSubscriber actual = new ReadStreamSubscriber<>(adapter);
multi.subscribe(actual);
return actual;
}
private final Function adapter;
private Handler endHandler;
private Handler exceptionHandler;
private Handler elementHandler;
private boolean paused = false;
private Throwable completed;
private ArrayDeque pending = new ArrayDeque<>();
private int requested = 0;
private Subscription subscription;
public ReadStreamSubscriber(Function adapter) {
this.adapter = adapter;
}
@Override
public ReadStream handler(Handler handler) {
synchronized (this) {
elementHandler = handler;
}
checkStatus();
return this;
}
@Override
public ReadStream pause() {
synchronized (this) {
paused = true;
}
return this;
}
@Override
public ReadStream fetch(long amount) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public ReadStream resume() {
synchronized (this) {
paused = false;
}
checkStatus();
return this;
}
@Override
public void onSubscribe(Subscription s) {
synchronized (this) {
subscription = s;
}
checkStatus();
}
private void checkStatus() {
Runnable action = NOOP_ACTION;
while (true) {
J adapted;
Handler handler;
synchronized (this) {
if (!paused && (handler = elementHandler) != null && pending.size() > 0) {
requested--;
R item = pending.poll();
adapted = adapter.apply(item);
} else {
if (completed != null) {
if (pending.isEmpty()) {
Handler onError;
Throwable result;
if (completed != DONE_SENTINEL) {
onError = exceptionHandler;
result = completed;
exceptionHandler = null;
} else {
onError = null;
result = null;
}
Handler onCompleted = endHandler;
endHandler = null;
action = () -> {
try {
if (onError != null) {
onError.handle(result);
}
} finally {
if (onCompleted != null) {
onCompleted.handle(null);
}
}
};
}
} else if (elementHandler != null && requested < BUFFER_SIZE / 2) {
int request = BUFFER_SIZE - requested;
action = () -> subscription.request(request);
requested = BUFFER_SIZE;
}
break;
}
}
handler.handle(adapted);
}
action.run();
}
@Override
public ReadStream endHandler(Handler handler) {
synchronized (this) {
if (completed == null || pending.size() > 0) {
endHandler = handler;
} else {
if (handler != null) {
throw new IllegalStateException();
}
}
}
return this;
}
@Override
public ReadStream exceptionHandler(Handler handler) {
synchronized (this) {
if (completed == null || pending.size() > 0) {
exceptionHandler = handler;
} else {
if (handler != null) {
throw new IllegalStateException();
}
}
}
return this;
}
@Override
public void onComplete() {
onError(DONE_SENTINEL);
}
@Override
public void onError(Throwable e) {
synchronized (this) {
if (completed != null) {
return;
}
completed = e;
}
checkStatus();
}
@Override
public void onNext(R item) {
synchronized (this) {
pending.add(item);
}
checkStatus();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy