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

io.smallrye.mutiny.vertx.ReadStreamSubscriber Maven / Gradle / Ivy

There is a newer version: 3.17.1
Show newest version
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