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

co.paralleluniverse.strands.channels.reactivestreams.ChannelProcessor Maven / Gradle / Ivy

/*
 * Quasar: lightweight threads and actors for the JVM.
 * Copyright (c) 2013-2015, Parallel Universe Software Co. All rights reserved.
 * 
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *  
 *   or (per the licensee's choosing)
 *  
 * under the terms of the GNU Lesser General Public License version 3.0
 * as published by the Free Software Foundation.
 */
package co.paralleluniverse.strands.channels.reactivestreams;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.FiberFactory;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.fibers.Suspendable;
import co.paralleluniverse.strands.SuspendableAction2;
import co.paralleluniverse.strands.SuspendableCallable;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.ProducerException;
import co.paralleluniverse.strands.channels.ReceivePort;
import co.paralleluniverse.strands.channels.SendPort;
import java.util.concurrent.atomic.AtomicInteger;
import org.reactivestreams.Processor;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

/**
 *
 * @author pron
 */
class ChannelProcessor implements Processor {
    private final ChannelSubscriber subscriber;
    private final ChannelPublisher publisher;

    private final FiberFactory ff;
    private final SuspendableAction2, ? extends SendPort> transformer;
    private final ReceivePort in;
    private final SendPort out;
    private final AtomicInteger connectedEnds = new AtomicInteger();
    private volatile Subscription subscription;

    public ChannelProcessor(FiberFactory ff, boolean batch, Channel in, Channel out, SuspendableAction2, ? extends SendPort> transformer) {
        this.ff = ff != null ? ff : defaultFiberFactory;
        this.transformer = transformer;
        this.subscriber = new ChannelSubscriber(in, batch) {
            @Override
            protected void failedSubscribe(Subscription s) {
                super.failedSubscribe(s);
                throw new FailedSubscriptionException();
            }
        };
        this.publisher = new ChannelPublisher(ff, out, true) {
            @Override
            protected void failedSubscribe(Subscriber s, Throwable t) {
                super.failedSubscribe(s, t);
                throw new FailedSubscriptionException();
            }

            @Override
            protected ChannelSubscription newChannelSubscription(Subscriber s, Object channel) {
                return new ChannelSubscription(s, (ReceivePort) channel) {
                    @Override
                    public void cancel() {
                        super.cancel();
                        Subscription ms = subscription;
                        if (ms != null)
                            ms.cancel();
                    }
                };
            }
        };
        this.in = subscriber;
        this.out = out;
    }

    private void connected() {
        int connections = connectedEnds.incrementAndGet();
        if (connections == 2)
            start();
        if (connections > 2)
            throw new AssertionError();
    }

    private void start() {
        ff.newFiber(new SuspendableCallable() {
            @Override
            public Void run() throws SuspendExecution, InterruptedException {
                try {
                    ((SuspendableAction2) transformer).call(in, out);
                    out.close();
                } catch (ProducerException e) {
                    out.close(e.getCause());
                } catch (Throwable t) {
                    out.close(t);
                }
                in.close();
                return null;
            }
        }).start();
    }

    @Override
    public void subscribe(Subscriber s) {
        try {
            publisher.subscribe(s);
            connected();
        } catch (FailedSubscriptionException e) {
        }
    }

    @Override
    public void onSubscribe(Subscription s) {
        try {
            subscriber.onSubscribe(s);
            this.subscription = s;
            connected();
        } catch (FailedSubscriptionException e) {
        }
    }

    @Override
    @Suspendable
    public void onNext(T element) {
        subscriber.onNext(element);
    }

    @Override
    public void onError(Throwable cause) {
        subscriber.onError(cause);
    }

    @Override
    public void onComplete() {
        subscriber.onComplete();
    }

    private static final FiberFactory defaultFiberFactory = new FiberFactory() {
        @Override
        public  Fiber newFiber(SuspendableCallable target) {
            return new Fiber(target);
        }
    };

    private static class FailedSubscriptionException extends RuntimeException {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy