diff --git a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java index 9f01b5e914..ec4646bff4 100644 --- a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java +++ b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java @@ -20,6 +20,7 @@ import static io.grpc.benchmarks.Utils.pickUnusedPort; import com.google.protobuf.ByteString; import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; import io.grpc.Server; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -30,7 +31,6 @@ import io.grpc.benchmarks.proto.Messages.SimpleResponse; import io.grpc.benchmarks.qps.AsyncServer; import io.grpc.inprocess.InProcessChannelBuilder; import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.internal.AbstractManagedChannelImplBuilder; import io.grpc.internal.AbstractServerImplBuilder; import io.grpc.netty.NegotiationType; import io.grpc.netty.NettyChannelBuilder; @@ -81,7 +81,7 @@ public class TransportBenchmark { @Setup public void setUp() throws Exception { AbstractServerImplBuilder serverBuilder; - AbstractManagedChannelImplBuilder channelBuilder; + ManagedChannelBuilder channelBuilder; switch (transport) { case INPROCESS: { diff --git a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java index b92fdf5410..aac6c25a8e 100644 --- a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java +++ b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java @@ -51,7 +51,7 @@ import java.util.logging.Logger; import javax.annotation.Nullable; /** - * The base class for channel builders. + * Abstract base class for channel builders. * * @param The concrete type of this builder. */ diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java b/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java new file mode 100644 index 0000000000..02af7ef048 --- /dev/null +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java @@ -0,0 +1,198 @@ +/* + * Copyright 2020 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.internal; + +import com.google.common.base.Preconditions; +import io.grpc.ManagedChannelBuilder; +import java.net.SocketAddress; +import java.util.concurrent.Executor; +import javax.annotation.Nullable; + +/** + * Default managed channel builder, for usage in Transport implementations. + */ +public final class ManagedChannelImplBuilder + extends AbstractManagedChannelImplBuilder { + + private boolean authorityCheckerDisabled; + @Deprecated + @Nullable + private OverrideAuthorityChecker authorityChecker; + + /** + * An interface for Transport implementors to provide the {@link ClientTransportFactory} + * appropriate for the channel. + */ + public interface ClientTransportFactoryBuilder { + ClientTransportFactory buildClientTransportFactory(); + } + + /** + * An interface for Transport implementors to provide a default port to {@link + * io.grpc.NameResolver} for use in cases where the target string doesn't include a port. The + * default implementation returns {@link GrpcUtil#DEFAULT_PORT_SSL}. + */ + public interface ChannelBuilderDefaultPortProvider { + int getDefaultPort(); + } + + /** + * Default implementation of {@link ChannelBuilderDefaultPortProvider} that returns a fixed port. + */ + public static final class FixedPortProvider implements ChannelBuilderDefaultPortProvider { + private final int port; + + public FixedPortProvider(int port) { + this.port = port; + } + + @Override + public int getDefaultPort() { + return port; + } + } + + private final class ManagedChannelDefaultPortProvider implements + ChannelBuilderDefaultPortProvider { + @Override + public int getDefaultPort() { + return ManagedChannelImplBuilder.super.getDefaultPort(); + } + } + + private final ClientTransportFactoryBuilder clientTransportFactoryBuilder; + private final ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider; + + /** + * Creates a new managed channel builder with a target string, which can be either a valid {@link + * io.grpc.NameResolver}-compliant URI, or an authority string. Transport implementors must + * provide client transport factory builder, and may set custom channel default port provider. + */ + public ManagedChannelImplBuilder(String target, + ClientTransportFactoryBuilder clientTransportFactoryBuilder, + @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { + super(target); + this.clientTransportFactoryBuilder = Preconditions + .checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder"); + + if (channelBuilderDefaultPortProvider != null) { + this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider; + } else { + this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider(); + } + } + + /** + * Creates a new managed channel builder with the given server address, authority string of the + * channel. Transport implementors must provide client transport factory builder, and may set + * custom channel default port provider. + */ + public ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority, + ClientTransportFactoryBuilder clientTransportFactoryBuilder, + @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { + super(directServerAddress, authority); + this.clientTransportFactoryBuilder = Preconditions + .checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder"); + + if (channelBuilderDefaultPortProvider != null) { + this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider; + } else { + this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider(); + } + } + + @Override + protected ClientTransportFactory buildTransportFactory() { + return clientTransportFactoryBuilder.buildClientTransportFactory(); + } + + @Override + protected int getDefaultPort() { + return channelBuilderDefaultPortProvider.getDefaultPort(); + } + + /** Disable the check whether the authority is valid. */ + public ManagedChannelImplBuilder disableCheckAuthority() { + authorityCheckerDisabled = true; + return this; + } + + /** Enable previously disabled authority check. */ + public ManagedChannelImplBuilder enableCheckAuthority() { + authorityCheckerDisabled = false; + return this; + } + + @Deprecated + public interface OverrideAuthorityChecker { + String checkAuthority(String authority); + } + + @Deprecated + public void overrideAuthorityChecker(@Nullable OverrideAuthorityChecker authorityChecker) { + this.authorityChecker = authorityChecker; + } + + @Override + protected String checkAuthority(String authority) { + if (authorityCheckerDisabled) { + return authority; + } + if (authorityChecker != null) { + return authorityChecker.checkAuthority(authority); + } + return super.checkAuthority(authority); + } + + @Override + public void setStatsEnabled(boolean value) { + super.setStatsEnabled(value); + } + + @Override + public void setStatsRecordStartedRpcs(boolean value) { + super.setStatsRecordStartedRpcs(value); + } + + @Override + public void setStatsRecordFinishedRpcs(boolean value) { + super.setStatsRecordFinishedRpcs(value); + } + + @Override + public void setStatsRecordRealTimeMetrics(boolean value) { + super.setStatsRecordRealTimeMetrics(value); + } + + @Override + public void setTracingEnabled(boolean value) { + super.setTracingEnabled(value); + } + + @Override + public ObjectPool getOffloadExecutorPool() { + return super.getOffloadExecutorPool(); + } + + public static ManagedChannelBuilder forAddress(String name, int port) { + throw new UnsupportedOperationException("ClientTransportFactoryBuilder is required"); + } + + public static ManagedChannelBuilder forTarget(String target) { + throw new UnsupportedOperationException("ClientTransportFactoryBuilder is required"); + } +} diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java new file mode 100644 index 0000000000..19a2f80096 --- /dev/null +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2020 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.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.grpc.internal.ManagedChannelImplBuilder.ChannelBuilderDefaultPortProvider; +import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; +import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit tests for {@link ManagedChannelImplBuilder}. */ +@RunWith(JUnit4.class) +public class ManagedChannelImplBuilderTest { + private static final int DUMMY_PORT = 42; + private static final String DUMMY_TARGET = "fake-target"; + private static final String DUMMY_AUTHORITY_VALID = "valid:1234"; + private static final String DUMMY_AUTHORITY_INVALID = "[ : : 1]"; + + @Rule public final MockitoRule mocks = MockitoJUnit.rule(); + @Rule public final ExpectedException thrown = ExpectedException.none(); + + @Mock private ClientTransportFactoryBuilder mockClientTransportFactoryBuilder; + @Mock private ChannelBuilderDefaultPortProvider mockChannelBuilderDefaultPortProvider; + private ManagedChannelImplBuilder builder; + + @Before + public void setUp() throws Exception { + builder = new ManagedChannelImplBuilder( + DUMMY_TARGET, + mockClientTransportFactoryBuilder, + mockChannelBuilderDefaultPortProvider); + } + + /** Ensure buildTransportFactory() delegates to the custom implementation. */ + @Test + public void buildTransportFactory() { + final ClientTransportFactory clientTransportFactory = mock(ClientTransportFactory.class); + when(mockClientTransportFactoryBuilder.buildClientTransportFactory()) + .thenReturn(clientTransportFactory); + assertEquals(clientTransportFactory, builder.buildTransportFactory()); + verify(mockClientTransportFactoryBuilder).buildClientTransportFactory(); + } + + /** Ensure getDefaultPort() returns default port when no custom implementation provided. */ + @Test + public void getDefaultPort_default() { + final ManagedChannelImplBuilder builderNoPortProvider = new ManagedChannelImplBuilder( + DUMMY_TARGET, mockClientTransportFactoryBuilder, null); + assertEquals(GrpcUtil.DEFAULT_PORT_SSL, builderNoPortProvider.getDefaultPort()); + } + + /** Ensure getDefaultPort() delegates to the custom implementation. */ + @Test + public void getDefaultPort_custom() { + when(mockChannelBuilderDefaultPortProvider.getDefaultPort()).thenReturn(DUMMY_PORT); + assertEquals(DUMMY_PORT, builder.getDefaultPort()); + verify(mockChannelBuilderDefaultPortProvider).getDefaultPort(); + } + + /** Test FixedPortProvider(int port). */ + @Test + public void getDefaultPort_fixedPortProvider() { + final ManagedChannelImplBuilder builderFixedPortProvider = new ManagedChannelImplBuilder( + DUMMY_TARGET, + mockClientTransportFactoryBuilder, + new FixedPortProvider(DUMMY_PORT)); + assertEquals(DUMMY_PORT, builderFixedPortProvider.getDefaultPort()); + } + + @Test + public void checkAuthority_validAuthorityAllowed() { + assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID)); + } + + @Test + public void checkAuthority_invalidAuthorityFailed() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Invalid authority"); + + builder.checkAuthority(DUMMY_AUTHORITY_INVALID); + } + + @Test + public void disableCheckAuthority_validAuthorityAllowed() { + builder.disableCheckAuthority(); + assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID)); + } + + @Test + public void disableCheckAuthority_invalidAuthorityAllowed() { + builder.disableCheckAuthority(); + assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID)); + } + + @Test + public void enableCheckAuthority_validAuthorityAllowed() { + builder.disableCheckAuthority().enableCheckAuthority(); + assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID)); + } + + @Test + public void disableCheckAuthority_invalidAuthorityFailed() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Invalid authority"); + + builder.disableCheckAuthority().enableCheckAuthority(); + builder.checkAuthority(DUMMY_AUTHORITY_INVALID); + } + + /** Ensure authority check can disabled with custom authority check implementation. */ + @Test + @SuppressWarnings("deprecation") + public void overrideAuthorityChecker_default() { + builder.overrideAuthorityChecker( + new io.grpc.internal.ManagedChannelImplBuilder.OverrideAuthorityChecker() { + @Override public String checkAuthority(String authority) { + return authority; + } + }); + assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID)); + } + + /** Ensure custom authority is ignored after disableCheckAuthority(). */ + @Test + @SuppressWarnings("deprecation") + public void overrideAuthorityChecker_ignored() { + builder.overrideAuthorityChecker( + new io.grpc.internal.ManagedChannelImplBuilder.OverrideAuthorityChecker() { + @Override public String checkAuthority(String authority) { + throw new IllegalArgumentException(); + } + }); + builder.disableCheckAuthority(); + assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID)); + } +} diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java index 2295dcb0ff..c551d26449 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java @@ -62,6 +62,7 @@ import io.grpc.NameResolver.ResolutionResult; import io.grpc.Status; import io.grpc.StringMarshaller; import io.grpc.internal.FakeClock.ScheduledTask; +import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; import io.grpc.internal.TestUtils.MockClientTransportInfo; import java.net.SocketAddress; import java.net.URI; @@ -159,21 +160,15 @@ public class ManagedChannelImplIdlenessTest { when(mockTransportFactory.getScheduledExecutorService()) .thenReturn(timer.getScheduledExecutorService()); - class Builder extends AbstractManagedChannelImplBuilder { - Builder(String target) { - super(target); - } + ManagedChannelImplBuilder builder = new ManagedChannelImplBuilder("fake://target", + new ClientTransportFactoryBuilder() { + @Override public ClientTransportFactory buildClientTransportFactory() { + throw new UnsupportedOperationException(); + } + }, + null); - @Override protected ClientTransportFactory buildTransportFactory() { - throw new UnsupportedOperationException(); - } - - @Override public Builder usePlaintext() { - throw new UnsupportedOperationException(); - } - } - - Builder builder = new Builder("fake://target") + builder .nameResolverFactory(mockNameResolverFactory) .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) .idleTimeout(IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS) diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index 3650911f14..ba17deba61 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -107,6 +107,8 @@ import io.grpc.StringMarshaller; import io.grpc.internal.ClientTransportFactory.ClientTransportOptions; import io.grpc.internal.InternalSubchannel.TransportLogger; import io.grpc.internal.ManagedChannelImpl.ScParser; +import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; +import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider; import io.grpc.internal.ServiceConfigUtil.PolicySelection; import io.grpc.internal.TestUtils.MockClientTransportInfo; import io.grpc.stub.ClientCalls; @@ -269,7 +271,7 @@ public class ManagedChannelImplTest { private CallCredentials creds; @Mock private Executor offloadExecutor; - private ChannelBuilder channelBuilder; + private ManagedChannelImplBuilder channelBuilder; private boolean requestConnection = true; private BlockingQueue transports; private boolean panicExpected; @@ -325,14 +327,20 @@ public class ManagedChannelImplTest { when(balancerRpcExecutorPool.getObject()) .thenReturn(balancerRpcExecutor.getScheduledExecutorService()); - channelBuilder = - new ChannelBuilder() - .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) - .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) - .userAgent(USER_AGENT) - .idleTimeout( - AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) - .offloadExecutor(offloadExecutor); + channelBuilder = new ManagedChannelImplBuilder(TARGET, + new ClientTransportFactoryBuilder() { + @Override + public ClientTransportFactory buildClientTransportFactory() { + throw new UnsupportedOperationException(); + } + }, + new FixedPortProvider(DEFAULT_PORT)); + channelBuilder + .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) + .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) + .userAgent(USER_AGENT) + .idleTimeout(ManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) + .offloadExecutor(offloadExecutor); channelBuilder.executorPool = executorPool; channelBuilder.binlog = null; channelBuilder.channelz = channelz; @@ -3466,21 +3474,18 @@ public class ManagedChannelImplTest { } FakeNameResolverFactory2 factory = new FakeNameResolverFactory2(); - final class CustomBuilder extends AbstractManagedChannelImplBuilder { - CustomBuilder() { - super(TARGET); - this.executorPool = ManagedChannelImplTest.this.executorPool; - this.channelz = ManagedChannelImplTest.this.channelz; - } - - @Override - protected ClientTransportFactory buildTransportFactory() { - return mockTransportFactory; - } - } - - ManagedChannel mychannel = new CustomBuilder().nameResolverFactory(factory).build(); + ManagedChannelImplBuilder customBuilder = new ManagedChannelImplBuilder(TARGET, + new ClientTransportFactoryBuilder() { + @Override + public ClientTransportFactory buildClientTransportFactory() { + return mockTransportFactory; + } + }, + null); + customBuilder.executorPool = executorPool; + customBuilder.channelz = channelz; + ManagedChannel mychannel = customBuilder.nameResolverFactory(factory).build(); ClientCall call1 = mychannel.newCall(TestMethodDescriptors.voidMethod(), CallOptions.DEFAULT); @@ -4025,22 +4030,6 @@ public class ManagedChannelImplTest { } } - private static final class ChannelBuilder - extends AbstractManagedChannelImplBuilder { - - ChannelBuilder() { - super(TARGET); - } - - @Override protected ClientTransportFactory buildTransportFactory() { - throw new UnsupportedOperationException(); - } - - @Override protected int getDefaultPort() { - return DEFAULT_PORT; - } - } - private static final class FakeBackoffPolicyProvider implements BackoffPolicy.Provider { @Override public BackoffPolicy get() { diff --git a/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java b/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java index de6098e5bd..49f094a6ad 100644 --- a/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java +++ b/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java @@ -46,6 +46,8 @@ import io.grpc.LoadBalancerRegistry; import io.grpc.NameResolver; import io.grpc.NameResolver.ConfigOrError; import io.grpc.Status; +import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; +import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider; import java.net.SocketAddress; import java.net.URI; import java.util.ArrayList; @@ -151,7 +153,7 @@ public class ServiceConfigErrorHandlingTest { private ObjectPool balancerRpcExecutorPool; @Mock private Executor blockingExecutor; - private ChannelBuilder channelBuilder; + private ManagedChannelImplBuilder channelBuilder; private void createChannel(ClientInterceptor... interceptors) { checkState(channel == null); @@ -197,14 +199,21 @@ public class ServiceConfigErrorHandlingTest { .thenReturn(timer.getScheduledExecutorService()); when(executorPool.getObject()).thenReturn(executor.getScheduledExecutorService()); - channelBuilder = - new ChannelBuilder() - .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) - .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) - .userAgent(USER_AGENT) - .idleTimeout( - AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) - .offloadExecutor(blockingExecutor); + channelBuilder = new ManagedChannelImplBuilder(TARGET, + new ClientTransportFactoryBuilder() { + @Override + public ClientTransportFactory buildClientTransportFactory() { + throw new UnsupportedOperationException(); + } + }, + new FixedPortProvider(DEFAULT_PORT)); + + channelBuilder + .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) + .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) + .userAgent(USER_AGENT) + .idleTimeout(ManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) + .offloadExecutor(blockingExecutor); channelBuilder.executorPool = executorPool; channelBuilder.binlog = null; channelBuilder.channelz = channelz; @@ -527,22 +536,6 @@ public class ServiceConfigErrorHandlingTest { verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class)); } - private static final class ChannelBuilder - extends AbstractManagedChannelImplBuilder { - - ChannelBuilder() { - super(TARGET); - } - - @Override protected ClientTransportFactory buildTransportFactory() { - throw new UnsupportedOperationException(); - } - - @Override protected int getDefaultPort() { - return DEFAULT_PORT; - } - } - private static final class FakeBackoffPolicyProvider implements BackoffPolicy.Provider { @Override public BackoffPolicy get() {