@Test public void workerOrchestrator() throws InterruptedException { Reactor reactor = Reactors.reactor(env, Environment.WORK_QUEUE); CountDownLatch latch = new CountDownLatch(3); reactor.on( Selectors.$("worker"), new Consumer() { @Override public void accept(Object o) { System.out.println(Thread.currentThread().getName() + " worker " + o); reactor.notify("orchestrator", Event.wrap(1000)); latch.countDown(); System.out.println(Thread.currentThread().getName() + " ok"); } }); reactor.on( Selectors.$("orchestrator"), new Consumer<Event<Integer>>() { @Override public void accept(Event<Integer> event) { sendTask(); } void sendTask() { System.out.println(Thread.currentThread().getName() + " sendTask "); reactor.notify("worker", Event.wrap(latch.getCount())); latch.countDown(); } }); reactor.notify("orchestrator", Event.wrap(1000)); Assert.isTrue(latch.await(10, TimeUnit.SECONDS)); }
/** * Subclasses should register the given {@link reactor.net.NetChannel} for later use. * * @param ioChannel The channel object. * @param netChannel The {@link NetChannel}. * @param <C> The type of the channel object. * @return {@link reactor.event.registry.Registration} of this channel in the {@link Registry}. */ protected <C> Registration<? extends NetChannel<IN, OUT>> register( @Nonnull C ioChannel, @Nonnull NetChannel<IN, OUT> netChannel) { Assert.notNull(ioChannel, "Channel cannot be null."); Assert.notNull(netChannel, "NetChannel cannot be null."); return netChannels.register(Selectors.$(ioChannel), netChannel); }
/** * Abstract base class that implements common functionality shared by clients and servers. * * @author Jon Brisbin */ public abstract class AbstractNetPeer<IN, OUT> { private final Registry<NetChannel<IN, OUT>> netChannels = new CachingRegistry<NetChannel<IN, OUT>>(); private final Event<AbstractNetPeer<IN, OUT>> 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<Buffer, IN, OUT> codec; private final Collection<Consumer<NetChannel<IN, OUT>>> consumers; protected AbstractNetPeer( @Nonnull Environment env, @Nonnull Reactor reactor, @Nullable Codec<Buffer, IN, OUT> codec, @Nonnull Collection<Consumer<NetChannel<IN, OUT>>> consumers) { this.env = env; this.reactor = reactor; this.codec = codec; this.consumers = consumers; for (final Consumer<NetChannel<IN, OUT>> consumer : consumers) { reactor.on( open, new Consumer<Event<NetChannel<IN, OUT>>>() { @Override public void accept(Event<NetChannel<IN, OUT>> ev) { consumer.accept(ev.getData()); } }); } } public Promise<Boolean> close() { Deferred<Boolean, Promise<Boolean>> d = Promises.defer(env, reactor.getDispatcher()); close(d); return d.compose(); } public void close(@Nullable final Consumer<Boolean> onClose) { reactor.schedule( new Consumer<Void>() { @Override public void accept(Void v) { for (Registration<? extends NetChannel<IN, OUT>> reg : getChannels()) { if (null == reg) { continue; } doCloseChannel(reg.getObject()); } getChannels().clear(); doClose(onClose); } }, null); } /** * Subclasses should register the given {@link reactor.net.NetChannel} for later use. * * @param ioChannel The channel object. * @param netChannel The {@link NetChannel}. * @param <C> The type of the channel object. * @return {@link reactor.event.registry.Registration} of this channel in the {@link Registry}. */ protected <C> Registration<? extends NetChannel<IN, OUT>> register( @Nonnull C ioChannel, @Nonnull NetChannel<IN, OUT> 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 <C> The type of the channel object. * @return The {@link NetChannel} associated with the given channel. */ protected <C> NetChannel<IN, OUT> select(@Nonnull C ioChannel) { Assert.notNull(ioChannel, "Channel cannot be null."); Iterator<Registration<? extends NetChannel<IN, OUT>>> channs = netChannels.select(ioChannel).iterator(); if (channs.hasNext()) { return channs.next().getObject(); } else { NetChannel<IN, OUT> conn = createChannel(ioChannel); register(ioChannel, conn); notifyOpen(conn); return conn; } } /** * Close the given channel. * * @param channel The channel object. * @param <C> The type of the channel object. */ protected <C> void close(@Nonnull C channel) { Assert.notNull(channel, "Channel cannot be null"); for (Registration<? extends NetChannel<IN, OUT>> reg : netChannels.select(channel)) { NetChannel<IN, OUT> 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 <C> The type of the channel object. * @return The new {@link NetChannel} object. */ protected abstract <C> NetChannel<IN, OUT> 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<Runnable>() { @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<IN, OUT> 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<IN, OUT> 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<Buffer, IN, OUT> getCodec() { return codec; } @Nonnull protected Environment getEnvironment() { return env; } @Nonnull protected Reactor getReactor() { return reactor; } @Nonnull protected Collection<Consumer<NetChannel<IN, OUT>>> getConsumers() { return consumers; } @Nonnull protected Registry<NetChannel<IN, OUT>> getChannels() { return netChannels; } /** * Subclasses should implement this method to perform the actual IO channel close. * * @param onClose */ protected void doClose(@Nullable Consumer<Boolean> onClose) { getReactor().schedule(onClose, null); } /** * Close the given channel. * * @param channel */ protected void doCloseChannel(NetChannel<IN, OUT> channel) { channel.close(); } }