@SuppressWarnings("unchecked") public <E> void dispatch( Object key, E event, Registry<Consumer<?>> consumerRegistry, Consumer<Throwable> errorConsumer, Router router, Consumer<E> completionConsumer, boolean isInContext) { Assert.isTrue(alive(), "This Dispatcher has been shut down."); try { Task task; if (isInContext) { task = allocateRecursiveTask(); } else { task = allocateTask(); } task.setKey(key) .setData(event) .setConsumerRegistry(consumerRegistry) .setErrorConsumer(errorConsumer) .setRouter(router); if (completionConsumer != null) task.setCompletionConsumer((Consumer<Object>) completionConsumer); if (!isInContext) { execute(task); } } catch (Exception e) { throw new IllegalStateException(e.getMessage() + " " + Thread.currentThread(), e); } }
protected Composable( @Nullable Environment env, @Nonnull Observable events, @Nullable Composable parent) { Assert.notNull(events, "Events Observable cannot be null."); this.env = env; this.events = events; this.parent = parent; }
/** * 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); } }
/** * 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; } }
/** * Assign the given {@link Function} to transform the incoming value {@code T} into a {@code V} * and pass it into another {@code Composable}. * * @param fn the transformation function * @param <V> the type of the return value of the transformation function * @return a new {@code Composable} containing the transformed values */ public <V> Composable<V> map(@Nonnull final Function<T, V> fn) { Assert.notNull(fn, "Map function cannot be null."); final Deferred<V, ? extends Composable<V>> d = createDeferred(); consume( new Consumer<T>() { @Override public void accept(T value) { try { V val = fn.apply(value); d.accept(val); } catch (Throwable e) { d.accept(e); } } }); return d.compose(); }
@SuppressWarnings("unchecked") @Override public <V> StateMachine<T> notify(final V state, final T value) { if (strict) { Assert.isTrue(states.contains(state), "State " + state + " has not been defined"); } Event<T> ev = Event.wrap(value instanceof Event ? ((Event<T>) value).getData() : value); observable.notify( state, ev, new Consumer<Event<T>>() { @Override public void accept(final Event<T> ev) { transition(state, ev.getData()); } }); return this; }
/** * Slice this buffer at the given positions. Useful for extracting multiple segments of data from * a buffer when the exact indices of that data is already known. * * @param positions The start and end positions of the slices. * @return A list of {@link View Views} pointing to the slices. */ public List<View> slice(int... positions) { Assert.notNull(positions, "Positions cannot be null."); if (positions.length == 0) { return Collections.emptyList(); } snapshot(); List<View> views = new ArrayList<View>(); int len = positions.length; for (int i = 0; i < len; i++) { int start = positions[i]; int end = (i + 1 < len ? positions[++i] : this.limit); views.add(createView(start, end)); reset(); } return views; }
/** * Evaluate each accepted value against the given {@link Predicate}. If the predicate test * succeeds, the value is passed into the new {@code Composable}. If the predicate test fails, an * exception is propagated into the new {@code Composable}. * * @param p the {@link Predicate} to test values against * @return a new {@code Composable} containing only values that pass the predicate test */ public Composable<T> filter(@Nonnull final Predicate<T> p) { Assert.notNull(p, "Filter predicate cannot be null."); final Deferred<T, ? extends Composable<T>> d = createDeferred(); consume( new Consumer<T>() { @Override public void accept(T value) { boolean b = p.test(value); if (b) { d.accept(value); } else { d.accept( new IllegalArgumentException( String.format("%s failed a predicate test.", value))); } } }); return d.compose(); }
/** * Create a {@code TcpClient.Spec} using the given implementation class. * * @param clientImpl The concrete implementation of {@link TcpClient} to instantiate. */ @SuppressWarnings({"unchecked", "rawtypes"}) public TcpClientSpec(@Nonnull Class<? extends TcpClient> clientImpl) { Assert.notNull(clientImpl, "TcpClient implementation class cannot be null."); try { this.clientImplConstructor = (Constructor<TcpClient<IN, OUT>>) clientImpl.getDeclaredConstructor( Environment.class, Reactor.class, InetSocketAddress.class, ClientSocketOptions.class, SslOptions.class, Codec.class, Collection.class); this.clientImplConstructor.setAccessible(true); } catch (NoSuchMethodException e) { throw new IllegalArgumentException( "No public constructor found that matches the signature of the one found in the TcpClient class."); } }
@Override public <V> StateMachine<T> on(final V state, final Function<T, T> fn) { if (strict) { Assert.isTrue(states.contains(state), "State " + state + " has not been defined"); } observable.on( (state instanceof Selector ? (Selector) state : Selectors.object(state)), new Consumer<Event<T>>() { @SuppressWarnings("unchecked") @Override public void accept(final Event<T> data) { try { data.setData(fn.apply(data.getData())); } catch (Throwable t) { observable.notify( t.getClass(), Event.wrap(new StateException(t, state, data.getData()))); } } }); return this; }
@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)); }
/** * Allow interceptors etc to publish events, perhaps subclasses of TcpConnectionEvent. The event * source must be this connection. * * @param event the event to publish. */ public void publishEvent(TcpConnectionEvent event) { Assert.isTrue(event.getData() == this, "Can only publish events with this as the source"); this.doPublish(event); }
protected NettyTcpServer( Environment env, Reactor reactor, InetSocketAddress listenAddress, final ServerSocketOptions opts, final SslOptions sslOpts, Codec<Buffer, IN, OUT> codec, Collection<Consumer<TcpConnection<IN, OUT>>> connectionConsumers) { super(env, reactor, listenAddress, opts, sslOpts, codec, connectionConsumers); this.eventsReactor = reactor; this.listenAddress = listenAddress; Assert.notNull(opts, "ServerSocketOptions cannot be null"); this.options = opts; int selectThreadCount = env.getProperty("reactor.tcp.selectThreadCount", Integer.class, Environment.PROCESSORS / 2); int ioThreadCount = env.getProperty("reactor.tcp.ioThreadCount", Integer.class, Environment.PROCESSORS); selectorGroup = new NioEventLoopGroup( selectThreadCount, new NamedDaemonThreadFactory("reactor-tcp-select")); ioGroup = new NioEventLoopGroup(ioThreadCount, new NamedDaemonThreadFactory("reactor-tcp-io")); this.bootstrap = new ServerBootstrap() .group(selectorGroup, ioGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, options.backlog()) .option(ChannelOption.SO_RCVBUF, options.rcvbuf()) .option(ChannelOption.SO_SNDBUF, options.sndbuf()) .option(ChannelOption.SO_REUSEADDR, options.reuseAddr()) .localAddress((null == listenAddress ? new InetSocketAddress(3000) : listenAddress)) .childHandler( new ChannelInitializer<SocketChannel>() { @Override public void initChannel(final SocketChannel ch) throws Exception { SocketChannelConfig config = ch.config(); config.setReceiveBufferSize(options.rcvbuf()); config.setSendBufferSize(options.sndbuf()); config.setKeepAlive(options.keepAlive()); config.setReuseAddress(options.reuseAddr()); config.setSoLinger(options.linger()); config.setTcpNoDelay(options.tcpNoDelay()); if (log.isDebugEnabled()) { log.debug("CONNECT {}", ch); } if (null != sslOpts) { SSLEngine ssl = new SSLEngineSupplier(sslOpts, false).get(); if (log.isDebugEnabled()) { log.debug( "SSL enabled using keystore {}", (null != sslOpts.keystoreFile() ? sslOpts.keystoreFile() : "<DEFAULT>")); } ch.pipeline().addLast(new SslHandler(ssl)); } if (options instanceof NettyServerSocketOptions && null != ((NettyServerSocketOptions) options).pipelineConfigurer()) { ((NettyServerSocketOptions) options) .pipelineConfigurer() .accept(ch.pipeline()); } ch.pipeline().addLast(createChannelHandlers(ch)); ch.closeFuture() .addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (log.isDebugEnabled()) { log.debug("CLOSE {}", ch); } close(ch); } }); } }); }
/** * 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); }
/** * 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)); }
/** * The address to which this client should connect. * * @param connectAddress The address to connect to. * @return {@literal this} */ public TcpClientSpec<IN, OUT> connect(@Nonnull InetSocketAddress connectAddress) { Assert.isNull(this.connectAddress, "Connect address is already set."); this.connectAddress = connectAddress; return this; }
/** * The {@link reactor.function.Consumer Consumers} to use to ingest the incoming data. * * @param consumers the incoming data {@link reactor.function.Consumer Consumers} * @return {@literal this} */ public TcpClientSpec<IN, OUT> consume(Collection<Consumer<IN>> consumers) { Assert.notNull(consumers, "Consumers cannot be null"); this.consumers = consumers; return this; }
/** * The {@link Codec} to use to encode and decode data. * * @param codec The codec to use. * @return {@literal this} */ public TcpClientSpec<IN, OUT> codec(@Nullable Codec<Buffer, IN, OUT> codec) { Assert.isNull(this.codec, "Codec has already been set."); this.codec = codec; return this; }