
reactor.net.AbstractNetPeer Maven / Gradle / Ivy
package reactor.net;
import com.gs.collections.impl.list.mutable.FastList;
import reactor.core.Environment;
import reactor.core.Reactor;
import reactor.core.composable.Deferred;
import reactor.core.composable.Promise;
import reactor.core.composable.spec.Promises;
import reactor.event.Event;
import reactor.event.registry.CachingRegistry;
import reactor.event.registry.Registration;
import reactor.event.registry.Registry;
import reactor.event.selector.Selector;
import reactor.event.selector.Selectors;
import reactor.function.Consumer;
import reactor.io.Buffer;
import reactor.io.encoding.Codec;
import reactor.util.Assert;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Iterator;
/**
* Abstract base class that implements common functionality shared by clients and servers.
*
* @author Jon Brisbin
*/
public abstract class AbstractNetPeer {
private final Registry> netChannels = new CachingRegistry>();
private final Event> selfEvent = Event.wrap(this);
private final Selector open = Selectors.$();
private final Selector close = Selectors.$();
private final Selector start = Selectors.$();
private final Selector shutdown = Selectors.$();
private final Environment env;
private final Reactor reactor;
private final Codec codec;
private final Collection>> consumers;
protected AbstractNetPeer(@Nonnull Environment env,
@Nonnull Reactor reactor,
@Nullable Codec codec,
@Nonnull Collection>> consumers) {
this.env = env;
this.reactor = reactor;
this.codec = codec;
this.consumers = consumers;
for (final Consumer> consumer : consumers) {
reactor.on(open, new Consumer>>() {
@Override
public void accept(Event> ev) {
consumer.accept(ev.getData());
}
});
}
}
public Promise close() {
Deferred> d = Promises.defer(env, reactor.getDispatcher());
close(d);
return d.compose();
}
public void close(@Nullable final Consumer onClose) {
for (Registration extends NetChannel> reg : getChannels()) {
if (!reg.isCancelled()) {
doCloseChannel(reg.getObject());
}
}
if (null != onClose) {
reactor.schedule(onClose, true);
}
}
public Iterator> iterator() {
FastList> channels = FastList.newList();
for (Registration extends NetChannel> reg : getChannels()) {
channels.add(reg.getObject());
}
return channels.iterator();
}
/**
* Subclasses should register the given {@link reactor.net.NetChannel} for later use.
*
* @param ioChannel
* The channel object.
* @param netChannel
* The {@link NetChannel}.
* @param
* The type of the channel object.
*
* @return {@link reactor.event.registry.Registration} of this channel in the {@link Registry}.
*/
protected Registration extends NetChannel> register(@Nonnull C ioChannel,
@Nonnull NetChannel netChannel) {
Assert.notNull(ioChannel, "Channel cannot be null.");
Assert.notNull(netChannel, "NetChannel cannot be null.");
return netChannels.register(Selectors.$(ioChannel), netChannel);
}
/**
* Find the {@link NetChannel} for the given IO channel object.
*
* @param ioChannel
* The channel object.
* @param
* The type of the channel object.
*
* @return The {@link NetChannel} associated with the given channel.
*/
protected NetChannel select(@Nonnull C ioChannel) {
Assert.notNull(ioChannel, "Channel cannot be null.");
Iterator>> channs = netChannels.select(ioChannel).iterator();
if (channs.hasNext()) {
return channs.next().getObject();
} else {
NetChannel conn = createChannel(ioChannel);
register(ioChannel, conn);
notifyOpen(conn);
return conn;
}
}
/**
* Close the given channel.
*
* @param channel
* The channel object.
* @param
* The type of the channel object.
*/
protected void close(@Nonnull C channel) {
Assert.notNull(channel, "Channel cannot be null");
for (Registration extends NetChannel> reg : netChannels.select(channel)) {
NetChannel chann = reg.getObject();
reg.cancel();
notifyClose(chann);
}
}
/**
* Subclasses should implement this method and provide a {@link NetChannel} object.
*
* @param ioChannel
* The IO channel object to associate with this {@link reactor.net.NetChannel}.
* @param
* The type of the channel object.
*
* @return The new {@link NetChannel} object.
*/
protected abstract NetChannel createChannel(C ioChannel);
/**
* Notify this server's consumers that the server has started.
*/
protected void notifyStart(final Runnable started) {
getReactor().notify(start.getObject(), selfEvent);
if (null != started) {
getReactor().schedule(new Consumer() {
@Override
public void accept(Runnable r) {
r.run();
}
}, started);
}
}
/**
* Notify this client's consumers than a global error has occurred.
*
* @param error
* The error to notify.
*/
protected void notifyError(@Nonnull Throwable error) {
Assert.notNull(error, "Error cannot be null.");
reactor.notify(error.getClass(), Event.wrap(error));
}
/**
* Notify this peer's consumers that the channel has been opened.
*
* @param channel
* The channel that was opened.
*/
protected void notifyOpen(@Nonnull NetChannel channel) {
reactor.notify(open.getObject(), Event.wrap(channel));
}
/**
* Notify this peer's consumers that the given channel has been closed.
*
* @param channel
* The channel that was closed.
*/
protected void notifyClose(@Nonnull NetChannel channel) {
reactor.notify(close.getObject(), Event.wrap(channel));
}
/**
* Notify this server's consumers that the server has stopped.
*/
protected void notifyShutdown() {
getReactor().notify(shutdown.getObject(), selfEvent);
}
/**
* Get the {@link Codec} in use.
*
* @return The codec. May be {@literal null}.
*/
@Nullable
protected Codec getCodec() {
return codec;
}
@Nonnull
protected Environment getEnvironment() {
return env;
}
@Nonnull
protected Reactor getReactor() {
return reactor;
}
@Nonnull
protected Collection>> getConsumers() {
return consumers;
}
@Nonnull
protected Registry> getChannels() {
return netChannels;
}
/**
* Subclasses should implement this method to perform the actual IO channel close.
*
* @param onClose
*/
protected void doClose(@Nullable Consumer onClose) {
getReactor().schedule(onClose, true);
}
/**
* Close the given channel.
*
* @param channel
*/
protected void doCloseChannel(NetChannel channel) {
channel.close();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy