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

co.paralleluniverse.strands.channels.reactivestreams.ChannelSubscriber 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.SuspendExecution;
import co.paralleluniverse.fibers.Suspendable;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.Timeout;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels.OverflowPolicy;
import co.paralleluniverse.strands.channels.QueueChannel;
import co.paralleluniverse.strands.channels.ReceivePort;
import java.util.concurrent.TimeUnit;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

/**
 *
 * @author pron
 */
class ChannelSubscriber implements Subscriber, ReceivePort {
    private final QueueChannel ch;
    private final long capacity;
    private Subscription subscription;
    private long consumed;
    private final boolean batch;

    public ChannelSubscriber(Channel channel, boolean batch) {
        if (!(channel instanceof QueueChannel))
            throw new IllegalArgumentException("Channel of type " + channel.getClass().getName() + " is not supported.");
        if (!((QueueChannel) channel).isSingleConsumer())
            throw new IllegalArgumentException("Provided channel must be single-consumer."); // #2.7
        this.ch = (QueueChannel) channel;
        this.capacity = (ch.capacity() < 0 || ch.getOverflowPolicy() == OverflowPolicy.DISPLACE) ? Long.MAX_VALUE : ch.capacity();
        this.batch = (capacity > 1 && capacity < Long.MAX_VALUE) ? batch : false;
    }

    @Override
    public void onSubscribe(Subscription s) {
        if (s == null)
            throw new NullPointerException(); // #2.13
        if (subscription != null)             // #2.5 TODO: concurrency?
            failedSubscribe(s);
        else {
            this.subscription = s;
            subscription.request(capacity);
        }
    }

    protected void failedSubscribe(Subscription s) {
        s.cancel();
    }

    @Override
    @Suspendable
    public void onNext(T element) {
        if (element == null)
            throw new NullPointerException(); // #2.13
        try {
            if (ch.isClosed())
                subscription.cancel();
            else
                ch.send(element);
        } catch (InterruptedException e) {
            Strand.interrupted();
        } catch (SuspendExecution e) {
            throw new AssertionError(e);
        }
    }

    @Override
    public void onError(Throwable cause) {
        if (cause == null)
            throw new NullPointerException(); // #2.13
        ch.close(cause);
    }

    @Override
    public void onComplete() {
        ch.close();
    }

    private void consumed() {
        if (capacity == Long.MAX_VALUE)
            return;

        if (!batch)
            subscription.request(1);
        else {
            if (++consumed >= capacity) {
                consumed = 0;
                subscription.request(capacity);
            }
        }
    }

    @Override
    public void close() {
        subscription.cancel();
        ch.close();
    }

    @Override
    public T receive() throws SuspendExecution, InterruptedException {
        T m = ch.receive();
        consumed();
        return m;
    }

    @Override
    public T receive(long timeout, TimeUnit unit) throws SuspendExecution, InterruptedException {
        T m = ch.receive(timeout, unit);
        if (m != null)
            consumed();
        return m;
    }

    @Override
    public T receive(Timeout timeout) throws SuspendExecution, InterruptedException {
        T m = ch.receive(timeout);
        if (m != null)
            consumed();
        return m;
    }

    @Override
    public T tryReceive() {
        T m = ch.tryReceive();
        if (m != null)
            consumed();
        return m;
    }

    @Override
    public boolean isClosed() {
        return ch.isClosed();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy