co.paralleluniverse.strands.channels.reactivestreams.ReactiveStreams Maven / Gradle / Ivy
Show all versions of quasar-reactive-streams Show documentation
/*
* 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.FiberFactory;
import co.paralleluniverse.strands.SuspendableAction2;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels;
import co.paralleluniverse.strands.channels.Channels.OverflowPolicy;
import co.paralleluniverse.strands.channels.ReceivePort;
import co.paralleluniverse.strands.channels.SendPort;
import co.paralleluniverse.strands.channels.Topic;
import org.reactivestreams.Processor;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
/**
* Converts between Quasar channels and reactive streams
* @author pron
*/
public class ReactiveStreams {
/**
* Subscribes to a given {@link Publisher} and return a {@link ReceivePort} to the subscription.
* This creates an internal single consumer channel that will receive the published elements.
*
* @param bufferSize the size of the buffer of the internal channel; may be {@code -1} for unbounded, but may not be {@code 0})
* @param policy the {@link OverflowPolicy} of the internal channel.
* @param publisher the subscriber
* @return A {@link ReceivePort} which emits the elements published by the subscriber
*/
public static ReceivePort subscribe(int bufferSize, OverflowPolicy policy, Publisher publisher) {
final Channel channel = Channels.newChannel(bufferSize, policy, true, true);
final ChannelSubscriber sub = new ChannelSubscriber<>(channel, false);
publisher.subscribe(sub);
return sub;
}
/**
* Turns a {@link ReceivePort channel} to a {@link Publisher}. All items sent to the channel will be published by
* the publisher.
*
* The publisher will allow a single subscription, unless the channel is a {@link Channels#isTickerChannel(ReceivePort) ticker channel}
* in which case, multiple subscribers will be allowed, and a new {@link Channels#newTickerConsumerFor(Channel) ticker consumer}
* will be created for each.
*
* Every subscription to the returned publisher creates an internal fiber, that will receive items from the
* channel and publish them.
*
* @param channel the channel
* @param ff the {@link FiberFactory} to create the internal fiber(s); if {@code null} then a default factory is used.
* @return a new publisher for the channel's items
*/
public static Publisher toPublisher(ReceivePort channel, FiberFactory ff) {
if (Channels.isTickerChannel(channel)) {
return new ChannelPublisher(ff, channel, false) {
@Override
protected ChannelSubscription newChannelSubscription(Subscriber super T> s, Object channel) {
return super.newChannelSubscription(s, Channels.newTickerConsumerFor((Channel) channel));
}
};
} else
return new ChannelPublisher(ff, channel, true);
}
/**
* Turns a {@link ReceivePort channel} to a {@link Publisher}. All items sent to the channel will be published by
* the publisher.
*
* The publisher will allow a single subscription, unless the channel is a {@link Channels#isTickerChannel(ReceivePort) ticker channel}
* in which case, multiple subscribers will be allowed, and a new {@link Channels#newTickerConsumerFor(Channel) ticker consumer}
* will be created for each.
*
* Every subscription to the returned publisher creates an internal fiber, that will receive items from the
* channel and publish them.
*
* Calling this method is the same as calling {@link #toPublisher(ReceivePort, FiberFactory) toPublisher(channel, null)
*
* @param channel the channel
* @return a new publisher for the channel's items
*/
public static Publisher toPublisher(ReceivePort channel) {
return toPublisher(channel, null);
}
/**
* Turns a {@link Topic topic} to a {@link Publisher}. All items sent to the topic will be published by
* the publisher.
*
* A new transfer channel (i.e. a blocking channel with a buffer of size 0) subscribed to the topic will be created for every subscriber.
*
* Every subscription to the returned publisher creates an internal fiber, that will receive items from the
* subscription's channel and publish them.
*
* @param topic the topic
* @param ff the {@link FiberFactory} to create the internal fiber(s); if {@code null} then a default factory is used.
* @return a new publisher for the topic's items
*/
public static Publisher toPublisher(Topic topic, final FiberFactory ff) {
return new ChannelPublisher(ff, topic, false) {
@Override
protected ChannelSubscription newChannelSubscription(Subscriber super T> s, Object channel) {
final Topic topic = (Topic) channel;
final Channel ch = Channels.newChannel(0);
try {
topic.subscribe(ch);
return new ChannelSubscription(s, ch) {
@Override
public void cancel() {
super.cancel();
topic.unsubscribe(ch);
}
};
} catch (Exception e) {
topic.unsubscribe(ch);
throw e;
}
}
};
}
/**
* Turns a {@link Topic topic} to a {@link Publisher}. All items sent to the topic will be published by
* the publisher.
*
* A new transfer channel (i.e. a blocking channel with a buffer of size 0) subscribed to the topic will be created for every subscriber.
*
* Every subscription to the returned publisher creates an internal fiber, that will receive items from the
* subscription's channel and publish them.
*
* Calling this method is the same as calling {@link #toPublisher(ReceivePort, FiberFactory) toPublisher(channel, null)
*
* @param topic the topic
* @return a new publisher for the topic's items
*/
public static Publisher toPublisher(Topic topic) {
return toPublisher(topic, null);
}
/**
* Turns a {@link Channels#fiberTransform(ReceivePort, SendPort, SuspendableAction2) transformer} into a {@link Publisher}.
* The transformer will run in its own fiber.
*
* @param the type of elements flowing into the transformer
* @param the type of elements flowing out of the transformer
* @param ff the {@link FiberFactory} to create the internal fiber(s); if {@code null} then a default factory is used.
* @param bufferSize the size of the buffer of the internal channel; may be {@code -1} for unbounded, but may not be {@code 0})
* @param policy the {@link OverflowPolicy} of the internal channel.
* @param batch if the channel has a bounded buffer, whether to request further elements from the publisher in batches
* whenever the channel's buffer is depleted, or after consuming each element.
* @param transformer a function that reads from it's input channel and writes to its output channel
* @return a {@code Processor} running the given transformer.
*/
public static Processor toProcessor(FiberFactory ff, int bufferSize, OverflowPolicy policy, SuspendableAction2 extends ReceivePort super T>, ? extends SendPort extends R>> transformer) {
final Channel in = Channels.newChannel(bufferSize, policy, true, true);
final Channel out = Channels.newChannel(bufferSize, policy, true, true);
return new ChannelProcessor(ff, false, in, out, transformer);
}
/**
* Turns a {@link Channels#fiberTransform(ReceivePort, SendPort, SuspendableAction2) transformer} into a {@link Publisher}.
* The transformer will run in its own fiber.
*
* Same as calling
* {@link #toProcessor(FiberFactory, int, OverflowPolicy, boolean, SuspendableAction2) toProcessor(null, bufferSize, policy, transformer)
*
* @param the type of elements flowing into the transformer
* @param the type of elements flowing out of the transformer
* @param ff the {@link FiberFactory} to create the internal fiber(s); if {@code null} then a default factory is used.
* @param bufferSize the size of the buffer of the internal channel; may be {@code -1} for unbounded, but may not be {@code 0})
* @param policy the {@link OverflowPolicy} of the internal channel.
* @param batch if the channel has a bounded buffer, whether to request further elements from the publisher in batches
* whenever the channel's buffer is depleted, or after consuming each element.
* @param transformer a function that reads from it's input channel and writes to its output channel
* @return a {@code Processor} running the given transformer.
*/
public static Processor toProcessor(int bufferSize, OverflowPolicy policy, SuspendableAction2 extends ReceivePort super T>, ? extends SendPort extends R>> transformer) {
return toProcessor(null, bufferSize, policy, transformer);
}
}