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

io.grpc.netty.NettyChannelBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 The gRPC Authors
 *
 * 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 io.grpc.netty;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;

import com.google.common.annotations.VisibleForTesting;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.grpc.Attributes;
import io.grpc.CallCredentials;
import io.grpc.ChannelCredentials;
import io.grpc.ChannelLogger;
import io.grpc.EquivalentAddressGroup;
import io.grpc.ExperimentalApi;
import io.grpc.HttpConnectProxiedSocketAddress;
import io.grpc.Internal;
import io.grpc.ManagedChannelBuilder;
import io.grpc.internal.AbstractManagedChannelImplBuilder;
import io.grpc.internal.AtomicBackoff;
import io.grpc.internal.ClientTransportFactory;
import io.grpc.internal.ConnectionClientTransport;
import io.grpc.internal.FixedObjectPool;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.KeepAliveManager;
import io.grpc.internal.ManagedChannelImplBuilder;
import io.grpc.internal.ManagedChannelImplBuilder.ChannelBuilderDefaultPortProvider;
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
import io.grpc.internal.ObjectPool;
import io.grpc.internal.SharedResourcePool;
import io.grpc.internal.TransportTracer;
import io.grpc.netty.ProtocolNegotiators.FromChannelCredentialsResult;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import javax.net.ssl.SSLException;

/**
 * A builder to help simplify construction of channels using the Netty transport.
 */
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
@CanIgnoreReturnValue
public final class NettyChannelBuilder extends
    AbstractManagedChannelImplBuilder {

  // 1MiB.
  public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1024 * 1024;
  private static final boolean DEFAULT_AUTO_FLOW_CONTROL;

  private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);

  private static final ChannelFactory DEFAULT_CHANNEL_FACTORY =
      new ReflectiveChannelFactory<>(Utils.DEFAULT_CLIENT_CHANNEL_TYPE);
  private static final ObjectPool DEFAULT_EVENT_LOOP_GROUP_POOL =
      SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP);

  static {
    String autoFlowControl = System.getenv("GRPC_EXPERIMENTAL_AUTOFLOWCONTROL");
    if (autoFlowControl == null) {
      autoFlowControl = "true";
    }
    DEFAULT_AUTO_FLOW_CONTROL = Boolean.parseBoolean(autoFlowControl);
  }

  private final ManagedChannelImplBuilder managedChannelImplBuilder;
  private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
  private final Map, Object> channelOptions = new HashMap<>();
  private ChannelFactory channelFactory = DEFAULT_CHANNEL_FACTORY;
  private ObjectPool eventLoopGroupPool = DEFAULT_EVENT_LOOP_GROUP_POOL;
  private boolean autoFlowControl = DEFAULT_AUTO_FLOW_CONTROL;
  private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
  private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
  private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
  private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
  private boolean keepAliveWithoutCalls;
  private ProtocolNegotiator.ClientFactory protocolNegotiatorFactory
      = new DefaultProtocolNegotiator();
  private final boolean freezeProtocolNegotiatorFactory;
  private LocalSocketPicker localSocketPicker;

  /**
   * If true, indicates that the transport may use the GET method for RPCs, and may include the
   * request body in the query params.
   */
  private final boolean useGetForSafeMethods = false;

  /**
   * Creates a new builder with the given server address. This factory method is primarily intended
   * for using Netty Channel types other than SocketChannel. {@link #forAddress(String, int)} should
   * generally be preferred over this method, since that API permits delaying DNS lookups and
   * noticing changes to DNS. If an unresolved InetSocketAddress is passed in, then it will remain
   * unresolved.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forAddress(SocketAddress serverAddress) {
    return new NettyChannelBuilder(serverAddress);
  }

  /**
   * Creates a new builder with the given server address. This factory method is primarily intended
   * for using Netty Channel types other than SocketChannel.
   * {@link #forAddress(String, int, ChannelCredentials)} should generally be preferred over this
   * method, since that API permits delaying DNS lookups and noticing changes to DNS. If an
   * unresolved InetSocketAddress is passed in, then it will remain unresolved.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forAddress(SocketAddress serverAddress,
      ChannelCredentials creds) {
    FromChannelCredentialsResult result = ProtocolNegotiators.from(creds);
    if (result.error != null) {
      throw new IllegalArgumentException(result.error);
    }
    return new NettyChannelBuilder(serverAddress, creds, result.callCredentials, result.negotiator);
  }

  /**
   * Creates a new builder with the given host and port.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forAddress(String host, int port) {
    return forTarget(GrpcUtil.authorityFromHostAndPort(host, port));
  }

  /**
   * Creates a new builder with the given host and port.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forAddress(String host, int port, ChannelCredentials creds) {
    return forTarget(GrpcUtil.authorityFromHostAndPort(host, port), creds);
  }

  /**
   * Creates a new builder with the given target string that will be resolved by
   * {@link io.grpc.NameResolver}.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forTarget(String target) {
    return new NettyChannelBuilder(target);
  }

  /**
   * Creates a new builder with the given target string that will be resolved by
   * {@link io.grpc.NameResolver}.
   */
  @CheckReturnValue
  public static NettyChannelBuilder forTarget(String target, ChannelCredentials creds) {
    FromChannelCredentialsResult result = ProtocolNegotiators.from(creds);
    if (result.error != null) {
      throw new IllegalArgumentException(result.error);
    }
    return new NettyChannelBuilder(target, creds, result.callCredentials, result.negotiator);
  }

  private final class NettyChannelTransportFactoryBuilder implements ClientTransportFactoryBuilder {
    @Override
    public ClientTransportFactory buildClientTransportFactory() {
      return buildTransportFactory();
    }
  }

  private final class NettyChannelDefaultPortProvider implements ChannelBuilderDefaultPortProvider {
    @Override
    public int getDefaultPort() {
      return protocolNegotiatorFactory.getDefaultPort();
    }
  }

  @CheckReturnValue
  NettyChannelBuilder(String target) {
    managedChannelImplBuilder = new ManagedChannelImplBuilder(target,
        new NettyChannelTransportFactoryBuilder(),
        new NettyChannelDefaultPortProvider());
    this.freezeProtocolNegotiatorFactory = false;
  }

  NettyChannelBuilder(
      String target, ChannelCredentials channelCreds, CallCredentials callCreds,
      ProtocolNegotiator.ClientFactory negotiator) {
    managedChannelImplBuilder = new ManagedChannelImplBuilder(
        target, channelCreds, callCreds,
        new NettyChannelTransportFactoryBuilder(),
        new NettyChannelDefaultPortProvider());
    this.protocolNegotiatorFactory = checkNotNull(negotiator, "negotiator");
    this.freezeProtocolNegotiatorFactory = true;
  }

  @CheckReturnValue
  NettyChannelBuilder(SocketAddress address) {
    managedChannelImplBuilder = new ManagedChannelImplBuilder(address,
        getAuthorityFromAddress(address),
        new NettyChannelTransportFactoryBuilder(),
        new NettyChannelDefaultPortProvider());
    this.freezeProtocolNegotiatorFactory = false;
  }

  NettyChannelBuilder(
      SocketAddress address, ChannelCredentials channelCreds, CallCredentials callCreds,
      ProtocolNegotiator.ClientFactory negotiator) {
    managedChannelImplBuilder = new ManagedChannelImplBuilder(address,
        getAuthorityFromAddress(address),
        channelCreds, callCreds,
        new NettyChannelTransportFactoryBuilder(),
        new NettyChannelDefaultPortProvider());
    this.protocolNegotiatorFactory = checkNotNull(negotiator, "negotiator");
    this.freezeProtocolNegotiatorFactory = true;
  }

  @Internal
  @Override
  protected ManagedChannelBuilder delegate() {
    return managedChannelImplBuilder;
  }

  @CheckReturnValue
  private static String getAuthorityFromAddress(SocketAddress address) {
    if (address instanceof InetSocketAddress) {
      InetSocketAddress inetAddress = (InetSocketAddress) address;
      return GrpcUtil.authorityFromHostAndPort(inetAddress.getHostString(), inetAddress.getPort());
    } else {
      return address.toString();
    }
  }

  /**
   * Specifies the channel type to use, by default we use {@code EpollSocketChannel} if available,
   * otherwise using {@link NioSocketChannel}.
   *
   * 

You either use this or {@link #channelFactory(io.netty.channel.ChannelFactory)} if your * {@link Channel} implementation has no no-args constructor. * *

It's an optional parameter. If the user has not provided an Channel type or ChannelFactory * when the channel is built, the builder will use the default one which is static. * *

You must also provide corresponding {@link #eventLoopGroup(EventLoopGroup)}. For example, * {@link NioSocketChannel} must use {@link io.netty.channel.nio.NioEventLoopGroup}, otherwise * your application won't start. */ public NettyChannelBuilder channelType(Class channelType) { checkNotNull(channelType, "channelType"); return channelFactory(new ReflectiveChannelFactory<>(channelType)); } /** * Specifies the {@link ChannelFactory} to create {@link Channel} instances. This method is * usually only used if the specific {@code Channel} requires complex logic which requires * additional information to create the {@code Channel}. Otherwise, recommend to use {@link * #channelType(Class)}. * *

It's an optional parameter. If the user has not provided an Channel type or ChannelFactory * when the channel is built, the builder will use the default one which is static. * *

You must also provide corresponding {@link #eventLoopGroup(EventLoopGroup)}. For example, * {@link NioSocketChannel} based {@link ChannelFactory} must use {@link * io.netty.channel.nio.NioEventLoopGroup}, otherwise your application won't start. */ public NettyChannelBuilder channelFactory(ChannelFactory channelFactory) { this.channelFactory = checkNotNull(channelFactory, "channelFactory"); return this; } /** * Specifies a channel option. As the underlying channel as well as network implementation may * ignore this value applications should consider it a hint. */ public NettyChannelBuilder withOption(ChannelOption option, T value) { channelOptions.put(option, value); return this; } /** * Sets the negotiation type for the HTTP/2 connection. * *

Default: TLS */ public NettyChannelBuilder negotiationType(NegotiationType type) { checkState(!freezeProtocolNegotiatorFactory, "Cannot change security when using ChannelCredentials"); if (!(protocolNegotiatorFactory instanceof DefaultProtocolNegotiator)) { // Do nothing for compatibility return this; } ((DefaultProtocolNegotiator) protocolNegotiatorFactory).negotiationType = type; return this; } /** * Provides an EventGroupLoop to be used by the netty transport. * *

It's an optional parameter. If the user has not provided an EventGroupLoop when the channel * is built, the builder will use the default one which is static. * *

You must also provide corresponding {@link #channelType(Class)} or {@link * #channelFactory(ChannelFactory)} corresponding to the given {@code EventLoopGroup}. For * example, {@link io.netty.channel.nio.NioEventLoopGroup} requires {@link NioSocketChannel} * *

The channel won't take ownership of the given EventLoopGroup. It's caller's responsibility * to shut it down when it's desired. */ public NettyChannelBuilder eventLoopGroup(@Nullable EventLoopGroup eventLoopGroup) { if (eventLoopGroup != null) { return eventLoopGroupPool(new FixedObjectPool<>(eventLoopGroup)); } return eventLoopGroupPool(DEFAULT_EVENT_LOOP_GROUP_POOL); } NettyChannelBuilder eventLoopGroupPool(ObjectPool eventLoopGroupPool) { this.eventLoopGroupPool = checkNotNull(eventLoopGroupPool, "eventLoopGroupPool"); return this; } /** * SSL/TLS context to use instead of the system default. It must have been configured with {@link * GrpcSslContexts}, but options could have been overridden. */ public NettyChannelBuilder sslContext(SslContext sslContext) { checkState(!freezeProtocolNegotiatorFactory, "Cannot change security when using ChannelCredentials"); if (sslContext != null) { checkArgument(sslContext.isClient(), "Server SSL context can not be used for client channel"); GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator()); } if (!(protocolNegotiatorFactory instanceof DefaultProtocolNegotiator)) { // Do nothing for compatibility return this; } ((DefaultProtocolNegotiator) protocolNegotiatorFactory).sslContext = sslContext; return this; } /** * Sets the initial flow control window in bytes. Setting initial flow control window enables auto * flow control tuning using bandwidth-delay product algorithm. To disable auto flow control * tuning, use {@link #flowControlWindow(int)}. By default, auto flow control is enabled with * initial flow control window size of {@link #DEFAULT_FLOW_CONTROL_WINDOW}. */ public NettyChannelBuilder initialFlowControlWindow(int initialFlowControlWindow) { checkArgument(initialFlowControlWindow > 0, "initialFlowControlWindow must be positive"); this.flowControlWindow = initialFlowControlWindow; this.autoFlowControl = true; return this; } /** * Sets the flow control window in bytes. Setting flowControlWindow disables auto flow control * tuning; use {@link #initialFlowControlWindow(int)} to enable auto flow control tuning. If not * called, the default value is {@link #DEFAULT_FLOW_CONTROL_WINDOW}) with auto flow control * tuning. */ public NettyChannelBuilder flowControlWindow(int flowControlWindow) { checkArgument(flowControlWindow > 0, "flowControlWindow must be positive"); this.flowControlWindow = flowControlWindow; this.autoFlowControl = false; return this; } /** * Sets the maximum size of header list allowed to be received. This is cumulative size of the * headers with some overhead, as defined for * * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE. The default is 8 KiB. * * @deprecated Use {@link #maxInboundMetadataSize} instead */ @Deprecated public NettyChannelBuilder maxHeaderListSize(int maxHeaderListSize) { return maxInboundMetadataSize(maxHeaderListSize); } /** * Sets the maximum size of metadata allowed to be received. This is cumulative size of the * entries with some overhead, as defined for * * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE. The default is 8 KiB. * * @param bytes the maximum size of received metadata * @return this * @throws IllegalArgumentException if bytes is non-positive * @since 1.17.0 */ @Override public NettyChannelBuilder maxInboundMetadataSize(int bytes) { checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0"); this.maxHeaderListSize = bytes; return this; } /** * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT}. */ @Override public NettyChannelBuilder usePlaintext() { negotiationType(NegotiationType.PLAINTEXT); return this; } /** * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code TLS}. */ @Override public NettyChannelBuilder useTransportSecurity() { negotiationType(NegotiationType.TLS); return this; } /** * {@inheritDoc} * * @since 1.3.0 */ @Override public NettyChannelBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) { checkArgument(keepAliveTime > 0L, "keepalive time must be positive"); keepAliveTimeNanos = timeUnit.toNanos(keepAliveTime); keepAliveTimeNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeNanos); if (keepAliveTimeNanos >= AS_LARGE_AS_INFINITE) { // Bump keepalive time to infinite. This disables keepalive. keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED; } return this; } /** * {@inheritDoc} * * @since 1.3.0 */ @Override public NettyChannelBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) { checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive"); keepAliveTimeoutNanos = timeUnit.toNanos(keepAliveTimeout); keepAliveTimeoutNanos = KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutNanos); return this; } /** * {@inheritDoc} * * @since 1.3.0 */ @Override public NettyChannelBuilder keepAliveWithoutCalls(boolean enable) { keepAliveWithoutCalls = enable; return this; } /** * If non-{@code null}, attempts to create connections bound to a local port. */ public NettyChannelBuilder localSocketPicker(@Nullable LocalSocketPicker localSocketPicker) { this.localSocketPicker = localSocketPicker; return this; } /** * This class is meant to be overriden with a custom implementation of * {@link #createSocketAddress}. The default implementation is a no-op. * * @since 1.16.0 */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4917") public static class LocalSocketPicker { /** * Called by gRPC to pick local socket to bind to. This may be called multiple times. * Subclasses are expected to override this method. * * @param remoteAddress the remote address to connect to. * @param attrs the Attributes present on the {@link io.grpc.EquivalentAddressGroup} associated * with the address. * @return a {@link SocketAddress} suitable for binding, or else {@code null}. * @since 1.16.0 */ @Nullable public SocketAddress createSocketAddress( SocketAddress remoteAddress, @EquivalentAddressGroup.Attr Attributes attrs) { return null; } } /** * Sets the maximum message size allowed for a single gRPC frame. If an inbound messages larger * than this limit is received it will not be processed and the RPC will fail with * RESOURCE_EXHAUSTED. */ @Override public NettyChannelBuilder maxInboundMessageSize(int max) { checkArgument(max >= 0, "negative max"); maxInboundMessageSize = max; return this; } @CheckReturnValue ClientTransportFactory buildTransportFactory() { assertEventLoopAndChannelType(); ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(); return new NettyTransportFactory( negotiator, channelFactory, channelOptions, eventLoopGroupPool, autoFlowControl, flowControlWindow, maxInboundMessageSize, maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls, transportTracerFactory, localSocketPicker, useGetForSafeMethods); } @VisibleForTesting void assertEventLoopAndChannelType() { boolean bothProvided = channelFactory != DEFAULT_CHANNEL_FACTORY && eventLoopGroupPool != DEFAULT_EVENT_LOOP_GROUP_POOL; boolean nonProvided = channelFactory == DEFAULT_CHANNEL_FACTORY && eventLoopGroupPool == DEFAULT_EVENT_LOOP_GROUP_POOL; checkState( bothProvided || nonProvided, "Both EventLoopGroup and ChannelType should be provided or neither should be"); } @CheckReturnValue int getDefaultPort() { return protocolNegotiatorFactory.getDefaultPort(); } @VisibleForTesting @CheckReturnValue static ProtocolNegotiator createProtocolNegotiatorByType( NegotiationType negotiationType, SslContext sslContext, ObjectPool executorPool) { switch (negotiationType) { case PLAINTEXT: return ProtocolNegotiators.plaintext(); case PLAINTEXT_UPGRADE: return ProtocolNegotiators.plaintextUpgrade(); case TLS: return ProtocolNegotiators.tls(sslContext, executorPool); default: throw new IllegalArgumentException("Unsupported negotiationType: " + negotiationType); } } NettyChannelBuilder disableCheckAuthority() { this.managedChannelImplBuilder.disableCheckAuthority(); return this; } NettyChannelBuilder enableCheckAuthority() { this.managedChannelImplBuilder.enableCheckAuthority(); return this; } void protocolNegotiatorFactory(ProtocolNegotiator.ClientFactory protocolNegotiatorFactory) { checkState(!freezeProtocolNegotiatorFactory, "Cannot change security when using ChannelCredentials"); this.protocolNegotiatorFactory = checkNotNull(protocolNegotiatorFactory, "protocolNegotiatorFactory"); } void setTracingEnabled(boolean value) { this.managedChannelImplBuilder.setTracingEnabled(value); } void setStatsEnabled(boolean value) { this.managedChannelImplBuilder.setStatsEnabled(value); } void setStatsRecordStartedRpcs(boolean value) { this.managedChannelImplBuilder.setStatsRecordStartedRpcs(value); } void setStatsRecordFinishedRpcs(boolean value) { this.managedChannelImplBuilder.setStatsRecordFinishedRpcs(value); } void setStatsRecordRealTimeMetrics(boolean value) { this.managedChannelImplBuilder.setStatsRecordRealTimeMetrics(value); } void setStatsRecordRetryMetrics(boolean value) { this.managedChannelImplBuilder.setStatsRecordRetryMetrics(value); } @VisibleForTesting NettyChannelBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) { this.transportTracerFactory = transportTracerFactory; return this; } private final class DefaultProtocolNegotiator implements ProtocolNegotiator.ClientFactory { private NegotiationType negotiationType = NegotiationType.TLS; private SslContext sslContext; @Override public ProtocolNegotiator newNegotiator() { SslContext localSslContext = sslContext; if (negotiationType == NegotiationType.TLS && localSslContext == null) { try { localSslContext = GrpcSslContexts.forClient().build(); } catch (SSLException ex) { throw new RuntimeException(ex); } } return createProtocolNegotiatorByType(negotiationType, localSslContext, managedChannelImplBuilder.getOffloadExecutorPool()); } @Override public int getDefaultPort() { switch (negotiationType) { case PLAINTEXT: case PLAINTEXT_UPGRADE: return GrpcUtil.DEFAULT_PORT_PLAINTEXT; case TLS: return GrpcUtil.DEFAULT_PORT_SSL; default: throw new AssertionError(negotiationType + " not handled"); } } } /** * Creates Netty transports. Exposed for internal use, as it should be private. */ @CheckReturnValue private static final class NettyTransportFactory implements ClientTransportFactory { private final ProtocolNegotiator protocolNegotiator; private final ChannelFactory channelFactory; private final Map, ?> channelOptions; private final ObjectPool groupPool; private final EventLoopGroup group; private final boolean autoFlowControl; private final int flowControlWindow; private final int maxMessageSize; private final int maxHeaderListSize; private final long keepAliveTimeNanos; private final AtomicBackoff keepAliveBackoff; private final long keepAliveTimeoutNanos; private final boolean keepAliveWithoutCalls; private final TransportTracer.Factory transportTracerFactory; private final LocalSocketPicker localSocketPicker; private final boolean useGetForSafeMethods; private boolean closed; NettyTransportFactory( ProtocolNegotiator protocolNegotiator, ChannelFactory channelFactory, Map, ?> channelOptions, ObjectPool groupPool, boolean autoFlowControl, int flowControlWindow, int maxMessageSize, int maxHeaderListSize, long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls, TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker, boolean useGetForSafeMethods) { this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator"); this.channelFactory = channelFactory; this.channelOptions = new HashMap, Object>(channelOptions); this.groupPool = groupPool; this.group = groupPool.getObject(); this.autoFlowControl = autoFlowControl; this.flowControlWindow = flowControlWindow; this.maxMessageSize = maxMessageSize; this.maxHeaderListSize = maxHeaderListSize; this.keepAliveTimeNanos = keepAliveTimeNanos; this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos); this.keepAliveTimeoutNanos = keepAliveTimeoutNanos; this.keepAliveWithoutCalls = keepAliveWithoutCalls; this.transportTracerFactory = transportTracerFactory; this.localSocketPicker = localSocketPicker != null ? localSocketPicker : new LocalSocketPicker(); this.useGetForSafeMethods = useGetForSafeMethods; } @Override public ConnectionClientTransport newClientTransport( SocketAddress serverAddress, ClientTransportOptions options, ChannelLogger channelLogger) { checkState(!closed, "The transport factory is closed."); ProtocolNegotiator localNegotiator = protocolNegotiator; HttpConnectProxiedSocketAddress proxiedAddr = options.getHttpConnectProxiedSocketAddress(); if (proxiedAddr != null) { serverAddress = proxiedAddr.getTargetAddress(); localNegotiator = ProtocolNegotiators.httpProxy( proxiedAddr.getProxyAddress(), proxiedAddr.getUsername(), proxiedAddr.getPassword(), protocolNegotiator); } final AtomicBackoff.State keepAliveTimeNanosState = keepAliveBackoff.getState(); Runnable tooManyPingsRunnable = new Runnable() { @Override public void run() { keepAliveTimeNanosState.backoff(); } }; // TODO(carl-mastrangelo): Pass channelLogger in. NettyClientTransport transport = new NettyClientTransport( serverAddress, channelFactory, channelOptions, group, localNegotiator, autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, keepAliveWithoutCalls, options.getAuthority(), options.getUserAgent(), tooManyPingsRunnable, transportTracerFactory.create(), options.getEagAttributes(), localSocketPicker, channelLogger, useGetForSafeMethods); return transport; } @Override public ScheduledExecutorService getScheduledExecutorService() { return group; } @Override public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials channelCreds) { checkNotNull(channelCreds, "channelCreds"); FromChannelCredentialsResult result = ProtocolNegotiators.from(channelCreds); if (result.error != null) { return null; } ClientTransportFactory factory = new NettyTransportFactory( result.negotiator.newNegotiator(), channelFactory, channelOptions, groupPool, autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls, transportTracerFactory, localSocketPicker, useGetForSafeMethods); return new SwapChannelCredentialsResult(factory, result.callCredentials); } @Override public void close() { if (closed) { return; } closed = true; protocolNegotiator.close(); groupPool.returnObject(group); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy