All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.ipc.netty.tcp.TcpClient Maven / Gradle / Ivy

There is a newer version: 0.7.15.RELEASE
Show newest version
/*
 * Copyright (c) 2011-2018 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.net.SocketAddress;
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;
import reactor.ipc.netty.resources.PoolResources;

/**
 * A TCP client connector.
 *
 * @author Stephane Maldini
 * @author Violeta Georgieva
 */
public class TcpClient implements NettyConnector {

	/**
	 * Bind a new TCP client to the localhost on {@link NettyOptions#DEFAULT_PORT port 12012}.
	 * 

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 {@link NettyOptions#DEFAULT_PORT port 12012}. *

The type of emitted data or received data is {@link ByteBuf} * * @param bindAddress the address to connect to on port 12012 * @return a new {@link TcpClient} */ public static TcpClient create(String bindAddress) { return create(bindAddress, NettyOptions.DEFAULT_PORT); } /** * Bind a new TCP client to "localhost" on the the specified port. *

The type of emitted data or received data is {@link ByteBuf} * * @param port the port to connect to on "localhost" * @return 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. *

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 * @return a new {@link TcpClient} */ public static TcpClient create(String bindAddress, int port) { return create(opts -> opts.host(bindAddress).port(port)); } /** * Bind a new TCP client to the specified connect address and port. *

The type of emitted data or received data is {@link ByteBuf} * * @param options {@link ClientOptions} configuration input * @return a new {@link TcpClient} */ public static TcpClient create(Consumer> options) { return builder().options(options).build(); } /** * Creates a builder for {@link TcpClient TcpClient} * * @return a new TcpClient builder */ public static TcpClient.Builder builder() { return new TcpClient.Builder(); } final ClientOptions options; protected TcpClient(TcpClient.Builder builder) { ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); if (Objects.nonNull(builder.options)) { builder.options.accept(clientOptionsBuilder); } if (!clientOptionsBuilder.isLoopAvailable()) { clientOptionsBuilder.loopResources(TcpResources.get()); } if (!clientOptionsBuilder.isPoolAvailable() && !clientOptionsBuilder.isPoolDisabled()) { clientOptionsBuilder.poolResources(TcpResources.get()); } this.options = clientOptionsBuilder.build(); } protected TcpClient(ClientOptions options) { this.options = Objects.requireNonNull(options, "options"); } @Override public final Mono newHandler(BiFunction> handler) { Objects.requireNonNull(handler, "handler"); return newHandler(handler, null, true, null); } /** * Get a copy of the {@link ClientOptions} currently in effect. * * @return the client options */ public final ClientOptions options() { return this.options.duplicate(); } @Override public String toString() { return "TcpClient: " + options.asSimpleString(); } /** * @param handler * @param address * @param secure * @param onSetup * * @return a new Mono to connect on subscribe */ protected Mono newHandler(BiFunction> handler, InetSocketAddress address, boolean secure, Consumer onSetup) { final BiFunction> targetHandler = null == handler ? ChannelOperations.noopHandler() : handler; return Mono.create(sink -> { SocketAddress remote = address != null ? address : options.getAddress(); ChannelPool pool = null; PoolResources poolResources = options.getPoolResources(); if (poolResources != null) { pool = poolResources.selectOrCreate(remote, options, doHandler(null, sink, secure, remote, null, null), options.getLoopResources().onClient(options.preferNative())); } ContextHandler contextHandler = doHandler(targetHandler, sink, secure, remote, pool, onSetup); sink.onCancel(contextHandler); if (pool == null) { Bootstrap b = options.get(); b.remoteAddress(remote); 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 doHandler(BiFunction> handler, MonoSink sink, boolean secure, SocketAddress providedAddress, ChannelPool pool, Consumer onSetup) { return ContextHandler.newClientContext(sink, options, loggingHandler, secure, providedAddress, pool, handler == null ? EMPTY : (ch, c, msg) -> ChannelOperations.bind(ch, handler, c)); } protected static final ChannelOperations.OnNew EMPTY = (a,b,c) -> null; static final LoggingHandler loggingHandler = new LoggingHandler(TcpClient.class); public static final class Builder { private Consumer> options; private Builder() { } /** * The options for the client, including address and port. * * @param options the options for the client, including address and port. * @return {@code this} */ public final Builder options(Consumer> options) { this.options = Objects.requireNonNull(options, "options"); return this; } public TcpClient build() { return new TcpClient(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy