Java tutorial
/* * Copyright (c) 2011-2016 Pivotal Software Inc, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package reactor.ipc.netty.tcp; import java.net.InetSocketAddress; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Consumer; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.pool.ChannelPool; import io.netty.channel.socket.SocketChannel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.NetUtil; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.core.publisher.MonoSink; import reactor.ipc.netty.NettyConnector; import reactor.ipc.netty.NettyContext; import reactor.ipc.netty.NettyInbound; import reactor.ipc.netty.NettyOutbound; import reactor.ipc.netty.channel.ChannelOperations; import reactor.ipc.netty.channel.ContextHandler; import reactor.ipc.netty.options.ClientOptions; import reactor.ipc.netty.options.NettyOptions; /** * A TCP client connector. * * @author Stephane Maldini */ public class TcpClient implements NettyConnector<NettyInbound, NettyOutbound> { /** * Bind a new TCP client to the localhost on port 12012. The default client * implementation is scanned from the classpath on Class init. * <p> The type of emitted data or received data is {@link ByteBuf} * * @return a new {@link TcpClient} */ public static TcpClient create() { return create(NetUtil.LOCALHOST.getHostAddress()); } /** * Bind a new TCP client to the specified connect address and port 12012. * <p> The type of emitted data or received data is {@link ByteBuf} * * @param bindAddress the address to connect to on port 12012 * <p> * a new {@link TcpClient} */ public static TcpClient create(String bindAddress) { return create(bindAddress, NettyOptions.DEFAULT_PORT); } /** * Bind a new TCP client to "loopback" on the the specified port. The default client * <p> The type of emitted data or received data is {@link ByteBuf} * * @param port the port to connect to on "loopback" * <p> * a new {@link TcpClient} */ public static TcpClient create(int port) { return create(NetUtil.LOCALHOST.getHostAddress(), port); } /** * Bind a new TCP client to the specified connect address and port. * <p> The type of emitted data or received data is {@link ByteBuf} * * @param bindAddress the address to connect to * @param port the port to connect to * <p> * a new {@link TcpClient} */ public static TcpClient create(String bindAddress, int port) { return create(opts -> opts.connect(bindAddress, port)); } /** * Bind a new TCP client to the specified connect address and port. * <p> The type of emitted data or received data is {@link ByteBuf} * * @param options a new {@link TcpClient} */ public static TcpClient create(Consumer<? super ClientOptions> options) { Objects.requireNonNull(options, "options"); ClientOptions clientOptions = ClientOptions.create(); clientOptions.loopResources(TcpResources.get()).poolResources(TcpResources.get()); options.accept(clientOptions); return new TcpClient(clientOptions.duplicate()); } final ClientOptions options; protected TcpClient(ClientOptions options) { this.options = Objects.requireNonNull(options, "options"); } /** * Get the {@link ClientOptions} currently in effect. * * @return the client options */ public final ClientOptions options() { return this.options; } @Override public final Mono<? extends NettyContext> newHandler( BiFunction<? super NettyInbound, ? super NettyOutbound, ? extends Publisher<Void>> handler) { Objects.requireNonNull(handler, "handler"); return newHandler(handler, null, true, null); } @Override public String toString() { return "TcpClient:" + options.toString(); } /** * @param handler * @param address * @param secure * @param onSetup * * @return a new Mono to connect on subscribe */ @SuppressWarnings("unchecked") protected Mono<NettyContext> newHandler( BiFunction<? super NettyInbound, ? super NettyOutbound, ? extends Publisher<Void>> handler, InetSocketAddress address, boolean secure, Consumer<? super Channel> onSetup) { final BiFunction<? super NettyInbound, ? super NettyOutbound, ? extends Publisher<Void>> targetHandler = null == handler ? ChannelOperations.noopHandler() : handler; return Mono.create(sink -> { ChannelPool pool = options.getPool(address); ContextHandler<SocketChannel> contextHandler = doHandler(targetHandler, sink, secure, pool, onSetup); if (pool == null) { Bootstrap b = options.get(address); b.handler(contextHandler); contextHandler.setFuture(b.connect()); } else { contextHandler.setFuture(pool.acquire()); } }); } /** * Create a {@link ContextHandler} for {@link Bootstrap#handler()} * * @param handler user provided in/out handler * @param sink user provided bind handler * @param secure if operation should be secured * @param pool if channel pool * @param onSetup if operation has local setup callback * * @return a new {@link ContextHandler} */ protected ContextHandler<SocketChannel> doHandler( BiFunction<? super NettyInbound, ? super NettyOutbound, ? extends Publisher<Void>> handler, MonoSink<NettyContext> sink, boolean secure, ChannelPool pool, Consumer<? super Channel> onSetup) { return ContextHandler.newClientContext(sink, options, loggingHandler, secure, pool, (ch, c, msg) -> ChannelOperations.bind(ch, handler, c)); } static final LoggingHandler loggingHandler = new LoggingHandler(TcpClient.class); }