blob: 29ce532c7fbf1240a2643b8b212f02f8059d7230 [file] [log] [blame]
lryan56e307f2014-12-05 13:25:08 -08001/*
Carl Mastrangelo3bfd6302017-05-31 13:29:01 -07002 * Copyright 2014, gRPC Authors All rights reserved.
lryan56e307f2014-12-05 13:25:08 -08003 *
Carl Mastrangelo3bfd6302017-05-31 13:29:01 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Carl Mastrangelo166108a2017-06-01 14:28:37 -07007 *
Carl Mastrangelo3bfd6302017-05-31 13:29:01 -07008 * http://www.apache.org/licenses/LICENSE-2.0
Carl Mastrangelo166108a2017-06-01 14:28:37 -07009 *
Carl Mastrangelo3bfd6302017-05-31 13:29:01 -070010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
lryan56e307f2014-12-05 13:25:08 -080015 */
16
nmittlerb687bdc2015-08-31 16:13:39 -070017package io.grpc.internal;
zhangkun8d6d12e2014-10-15 13:04:19 -070018
Kun Zhang527fd672016-06-17 09:47:41 -070019import static com.google.common.base.Preconditions.checkArgument;
Carl Mastrangelo82a79d82015-12-07 14:40:11 -080020
Kun Zhang631a9d52016-06-02 16:47:36 -070021import com.google.common.annotations.VisibleForTesting;
Kun Zhang942f4c92015-09-04 17:21:44 -070022import com.google.common.base.Preconditions;
buchgr602473d2015-11-11 12:53:08 +010023import com.google.common.util.concurrent.MoreExecutors;
Kun Zhangcce8eac2017-01-05 10:48:13 -080024import com.google.instrumentation.stats.Stats;
25import com.google.instrumentation.stats.StatsContextFactory;
Kun Zhang49bde542017-04-25 13:53:29 -070026import com.google.instrumentation.trace.Tracing;
Kun Zhang942f4c92015-09-04 17:21:44 -070027import io.grpc.Attributes;
28import io.grpc.ClientInterceptor;
ZHANG Dapeng7d048af2017-05-02 16:21:43 -070029import io.grpc.ClientStreamTracer;
Carl Mastrangelo82a79d82015-12-07 14:40:11 -080030import io.grpc.CompressorRegistry;
31import io.grpc.DecompressorRegistry;
Kun Zhang418d52d2017-03-22 18:29:31 -070032import io.grpc.EquivalentAddressGroup;
Kun Zhanga9bd9472017-02-21 17:11:03 -080033import io.grpc.LoadBalancer;
Kun Zhangd17a7b52017-01-10 15:30:12 -080034import io.grpc.ManagedChannel;
Kun Zhang942f4c92015-09-04 17:21:44 -070035import io.grpc.ManagedChannelBuilder;
36import io.grpc.NameResolver;
Eric Andersonfaa0ad72017-06-07 12:18:27 -070037import io.grpc.NameResolverProvider;
Kun Zhanga9bd9472017-02-21 17:11:03 -080038import io.grpc.PickFirstBalancerFactory;
Kun Zhang942f4c92015-09-04 17:21:44 -070039import java.net.SocketAddress;
40import java.net.URI;
Kun Zhang631a9d52016-06-02 16:47:36 -070041import java.net.URISyntaxException;
Eric Anderson0df3d5e2015-06-25 18:00:00 -070042import java.util.ArrayList;
43import java.util.Arrays;
Kun Zhang942f4c92015-09-04 17:21:44 -070044import java.util.Collections;
Eric Anderson0df3d5e2015-06-25 18:00:00 -070045import java.util.List;
Louis Ryan6a782a02015-09-03 14:27:48 -070046import java.util.concurrent.Executor;
Kun Zhang527fd672016-06-17 09:47:41 -070047import java.util.concurrent.TimeUnit;
zhangkun8d6d12e2014-10-15 13:04:19 -070048import javax.annotation.Nullable;
49
50/**
51 * The base class for channel builders.
nathanmittler0304b3d2014-10-24 13:39:13 -070052 *
nmittlerb687bdc2015-08-31 16:13:39 -070053 * @param <T> The concrete type of this builder.
zhangkun8d6d12e2014-10-15 13:04:19 -070054 */
nmittlerb687bdc2015-08-31 16:13:39 -070055public abstract class AbstractManagedChannelImplBuilder
56 <T extends AbstractManagedChannelImplBuilder<T>> extends ManagedChannelBuilder<T> {
Kun Zhang16247152015-12-08 17:52:05 -080057 private static final String DIRECT_ADDRESS_SCHEME = "directaddress";
Eric Andersonaeeebb72014-12-19 16:41:03 -080058
Kun Zhang527fd672016-06-17 09:47:41 -070059 /**
60 * An idle timeout larger than this would disable idle mode.
61 */
62 @VisibleForTesting
63 static final long IDLE_MODE_MAX_TIMEOUT_DAYS = 30;
64
65 /**
Kun Zhangd74091f2016-09-16 22:34:27 -070066 * The default idle timeout.
67 */
68 @VisibleForTesting
69 static final long IDLE_MODE_DEFAULT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(30);
70
71 /**
Kun Zhang527fd672016-06-17 09:47:41 -070072 * An idle timeout smaller than this would be capped to it.
73 */
74 @VisibleForTesting
75 static final long IDLE_MODE_MIN_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1);
76
Eric Anderson0a8d7612017-05-23 11:08:34 -070077 private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL =
78 SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR);
79
80 private static final NameResolver.Factory DEFAULT_NAME_RESOLVER_FACTORY =
81 NameResolverProvider.asFactory();
82
83 private static final LoadBalancer.Factory DEFAULT_LOAD_BALANCER_FACTORY =
84 PickFirstBalancerFactory.getInstance();
85
86 private static final DecompressorRegistry DEFAULT_DECOMPRESSOR_REGISTRY =
87 DecompressorRegistry.getDefaultInstance();
88
89 private static final CompressorRegistry DEFAULT_COMPRESSOR_REGISTRY =
90 CompressorRegistry.getDefaultInstance();
91
92 ObjectPool<? extends Executor> executorPool = DEFAULT_EXECUTOR_POOL;
Kun Zhangd17a7b52017-01-10 15:30:12 -080093
Eric Anderson0df3d5e2015-06-25 18:00:00 -070094 private final List<ClientInterceptor> interceptors = new ArrayList<ClientInterceptor>();
zhangkun8d6d12e2014-10-15 13:04:19 -070095
zpencer726c23b2017-06-16 18:54:47 -070096 // Access via getter, which may perform authority override as needed
97 private NameResolver.Factory nameResolverFactory = DEFAULT_NAME_RESOLVER_FACTORY;
98
Eric Anderson0a8d7612017-05-23 11:08:34 -070099 final String target;
Kun Zhang942f4c92015-09-04 17:21:44 -0700100
101 @Nullable
102 private final SocketAddress directServerAddress;
103
nmittler8c1d38a2015-06-01 08:31:00 -0700104 @Nullable
Eric Anderson0a8d7612017-05-23 11:08:34 -0700105 String userAgent;
nmittler8c1d38a2015-06-01 08:31:00 -0700106
zpencer726c23b2017-06-16 18:54:47 -0700107 @VisibleForTesting
Kun Zhang942f4c92015-09-04 17:21:44 -0700108 @Nullable
Eric Anderson0a8d7612017-05-23 11:08:34 -0700109 String authorityOverride;
Kun Zhang942f4c92015-09-04 17:21:44 -0700110
Kun Zhang942f4c92015-09-04 17:21:44 -0700111
Eric Anderson0a8d7612017-05-23 11:08:34 -0700112 LoadBalancer.Factory loadBalancerFactory = DEFAULT_LOAD_BALANCER_FACTORY;
Kun Zhang942f4c92015-09-04 17:21:44 -0700113
Eric Anderson0a8d7612017-05-23 11:08:34 -0700114 DecompressorRegistry decompressorRegistry = DEFAULT_DECOMPRESSOR_REGISTRY;
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800115
Eric Anderson0a8d7612017-05-23 11:08:34 -0700116 CompressorRegistry compressorRegistry = DEFAULT_COMPRESSOR_REGISTRY;
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800117
Eric Anderson0a8d7612017-05-23 11:08:34 -0700118 long idleTimeoutMillis = IDLE_MODE_DEFAULT_TIMEOUT_MILLIS;
Kun Zhang527fd672016-06-17 09:47:41 -0700119
Carl Mastrangelofdd062c2016-10-26 16:55:41 -0700120 private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
121
Kun Zhangbe74e972017-04-26 10:50:55 -0700122 private boolean enableStatsTagPropagation;
123 private boolean enableTracing;
124
zpencer347eb092017-05-17 17:12:45 -0700125 /**
126 * Sets the maximum message size allowed for a single gRPC frame. If an inbound messages
127 * larger than this limit is received it will not be processed and the RPC will fail with
128 * RESOURCE_EXHAUSTED.
129 */
Carl Mastrangelofdd062c2016-10-26 16:55:41 -0700130 // Can be overriden by subclasses.
131 @Override
132 public T maxInboundMessageSize(int max) {
133 checkArgument(max >= 0, "negative max");
134 maxInboundMessageSize = max;
135 return thisT();
136 }
137
138 protected final int maxInboundMessageSize() {
139 return maxInboundMessageSize;
140 }
141
Kun Zhang132f7a92016-10-06 17:15:24 -0700142 @Nullable
Kun Zhangcce8eac2017-01-05 10:48:13 -0800143 private StatsContextFactory statsFactory;
Kun Zhang132f7a92016-10-06 17:15:24 -0700144
Kun Zhangefac6792015-10-22 14:59:44 -0700145 protected AbstractManagedChannelImplBuilder(String target) {
Carl Mastrangelo12854772016-08-12 14:52:00 -0700146 this.target = Preconditions.checkNotNull(target, "target");
Kun Zhang942f4c92015-09-04 17:21:44 -0700147 this.directServerAddress = null;
148 }
149
Kun Zhang631a9d52016-06-02 16:47:36 -0700150 /**
151 * Returns a target string for the SocketAddress. It is only used as a placeholder, because
152 * DirectAddressNameResolverFactory will not actually try to use it. However, it must be a valid
153 * URI.
154 */
155 @VisibleForTesting
156 static String makeTargetStringForDirectAddress(SocketAddress address) {
157 try {
158 return new URI(DIRECT_ADDRESS_SCHEME, "", "/" + address, null).toString();
159 } catch (URISyntaxException e) {
160 // It should not happen.
161 throw new RuntimeException(e);
162 }
163 }
164
Kun Zhang942f4c92015-09-04 17:21:44 -0700165 protected AbstractManagedChannelImplBuilder(SocketAddress directServerAddress, String authority) {
Kun Zhang631a9d52016-06-02 16:47:36 -0700166 this.target = makeTargetStringForDirectAddress(directServerAddress);
Kun Zhang942f4c92015-09-04 17:21:44 -0700167 this.directServerAddress = directServerAddress;
168 this.nameResolverFactory = new DirectAddressNameResolverFactory(directServerAddress, authority);
169 }
170
Eric Anderson6122daf2015-09-03 12:14:30 -0700171 @Override
buchgr602473d2015-11-11 12:53:08 +0100172 public final T directExecutor() {
173 return executor(MoreExecutors.directExecutor());
174 }
175
176 @Override
Louis Ryan6a782a02015-09-03 14:27:48 -0700177 public final T executor(Executor executor) {
Eric Anderson0a8d7612017-05-23 11:08:34 -0700178 if (executor != null) {
179 this.executorPool = new FixedObjectPool<Executor>(executor);
180 } else {
181 this.executorPool = DEFAULT_EXECUTOR_POOL;
182 }
Eric Anderson0df3d5e2015-06-25 18:00:00 -0700183 return thisT();
184 }
185
Eric Anderson6122daf2015-09-03 12:14:30 -0700186 @Override
nmittlerb687bdc2015-08-31 16:13:39 -0700187 public final T intercept(List<ClientInterceptor> interceptors) {
Eric Anderson0df3d5e2015-06-25 18:00:00 -0700188 this.interceptors.addAll(interceptors);
189 return thisT();
190 }
191
Eric Anderson6122daf2015-09-03 12:14:30 -0700192 @Override
nmittlerb687bdc2015-08-31 16:13:39 -0700193 public final T intercept(ClientInterceptor... interceptors) {
Eric Anderson0df3d5e2015-06-25 18:00:00 -0700194 return intercept(Arrays.asList(interceptors));
195 }
196
Kun Zhang942f4c92015-09-04 17:21:44 -0700197 @Override
198 public final T nameResolverFactory(NameResolver.Factory resolverFactory) {
199 Preconditions.checkState(directServerAddress == null,
200 "directServerAddress is set (%s), which forbids the use of NameResolverFactory",
201 directServerAddress);
Eric Anderson0a8d7612017-05-23 11:08:34 -0700202 if (resolverFactory != null) {
203 this.nameResolverFactory = resolverFactory;
204 } else {
205 this.nameResolverFactory = DEFAULT_NAME_RESOLVER_FACTORY;
206 }
Kun Zhang942f4c92015-09-04 17:21:44 -0700207 return thisT();
208 }
209
210 @Override
Kun Zhanga9bd9472017-02-21 17:11:03 -0800211 public final T loadBalancerFactory(LoadBalancer.Factory loadBalancerFactory) {
Kun Zhang942f4c92015-09-04 17:21:44 -0700212 Preconditions.checkState(directServerAddress == null,
Kun Zhanga9bd9472017-02-21 17:11:03 -0800213 "directServerAddress is set (%s), which forbids the use of LoadBalancer.Factory",
Kun Zhang942f4c92015-09-04 17:21:44 -0700214 directServerAddress);
Eric Anderson0a8d7612017-05-23 11:08:34 -0700215 if (loadBalancerFactory != null) {
216 this.loadBalancerFactory = loadBalancerFactory;
217 } else {
218 this.loadBalancerFactory = DEFAULT_LOAD_BALANCER_FACTORY;
219 }
Kun Zhangd17a7b52017-01-10 15:30:12 -0800220 return thisT();
221 }
222
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800223 @Override
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800224 public final T decompressorRegistry(DecompressorRegistry registry) {
Eric Anderson0a8d7612017-05-23 11:08:34 -0700225 if (registry != null) {
226 this.decompressorRegistry = registry;
227 } else {
228 this.decompressorRegistry = DEFAULT_DECOMPRESSOR_REGISTRY;
229 }
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800230 return thisT();
231 }
232
233 @Override
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800234 public final T compressorRegistry(CompressorRegistry registry) {
Eric Anderson0a8d7612017-05-23 11:08:34 -0700235 if (registry != null) {
236 this.compressorRegistry = registry;
237 } else {
238 this.compressorRegistry = DEFAULT_COMPRESSOR_REGISTRY;
239 }
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800240 return thisT();
241 }
242
Eric Anderson6122daf2015-09-03 12:14:30 -0700243 @Override
Carl Mastrangelo1cc76d82016-05-24 16:29:26 -0700244 public final T userAgent(@Nullable String userAgent) {
nmittler8c1d38a2015-06-01 08:31:00 -0700245 this.userAgent = userAgent;
nmittlerb687bdc2015-08-31 16:13:39 -0700246 return thisT();
nmittler8c1d38a2015-06-01 08:31:00 -0700247 }
248
Eric Anderson6122daf2015-09-03 12:14:30 -0700249 @Override
Kun Zhang942f4c92015-09-04 17:21:44 -0700250 public final T overrideAuthority(String authority) {
251 this.authorityOverride = checkAuthority(authority);
252 return thisT();
253 }
254
Kun Zhang527fd672016-06-17 09:47:41 -0700255 @Override
256 public final T idleTimeout(long value, TimeUnit unit) {
257 checkArgument(value > 0, "idle timeout is %s, but must be positive", value);
258 // We convert to the largest unit to avoid overflow
259 if (unit.toDays(value) >= IDLE_MODE_MAX_TIMEOUT_DAYS) {
260 // This disables idle mode
Kun Zhanga9bd9472017-02-21 17:11:03 -0800261 this.idleTimeoutMillis = ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE;
Kun Zhang527fd672016-06-17 09:47:41 -0700262 } else {
263 this.idleTimeoutMillis = Math.max(unit.toMillis(value), IDLE_MODE_MIN_TIMEOUT_MILLIS);
264 }
265 return thisT();
266 }
267
Kun Zhang132f7a92016-10-06 17:15:24 -0700268 /**
Kun Zhang737cd162017-01-20 17:20:44 -0800269 * Override the default stats implementation.
Kun Zhang132f7a92016-10-06 17:15:24 -0700270 */
271 @VisibleForTesting
Kun Zhang903197b2017-04-07 11:03:24 -0700272 protected final T statsContextFactory(StatsContextFactory statsFactory) {
Kun Zhangcce8eac2017-01-05 10:48:13 -0800273 this.statsFactory = statsFactory;
Kun Zhang132f7a92016-10-06 17:15:24 -0700274 return thisT();
275 }
276
Kun Zhang903197b2017-04-07 11:03:24 -0700277 /**
278 * Indicates whether this transport will record stats with {@link ClientStreamTracer}.
279 *
280 * <p>By default it returns {@code true}. If the transport doesn't record stats, it may override
281 * this method to return {@code false} so that the builder won't install the Census interceptor.
282 *
283 * <p>If it returns true when it shouldn't be, Census will receive incomplete stats.
284 */
285 protected boolean recordsStats() {
286 return true;
287 }
288
Kun Zhang527fd672016-06-17 09:47:41 -0700289 @VisibleForTesting
290 final long getIdleTimeoutMillis() {
291 return idleTimeoutMillis;
292 }
293
Kun Zhang942f4c92015-09-04 17:21:44 -0700294 /**
295 * Verifies the authority is valid. This method exists as an escape hatch for putting in an
296 * authority that is valid, but would fail the default validation provided by this
297 * implementation.
298 */
299 protected String checkAuthority(String authority) {
300 return GrpcUtil.checkAuthority(authority);
301 }
302
Kun Zhangbe74e972017-04-26 10:50:55 -0700303 /**
304 * Set it to true to propagate the stats tags on the wire. This will be deleted assuming always
305 * enabled once the instrumentation-java wire format is stabilized.
306 */
307 @Deprecated
308 public void setEnableStatsTagPropagation(boolean enabled) {
309 this.enableStatsTagPropagation = enabled;
310 }
311
312 /**
313 * Set it to true to record traces and propagate tracing information on the wire. This will be
314 * deleted assuming always enabled once the instrumentation-java wire format is stabilized.
315 */
316 @Deprecated
317 public void setEnableTracing(boolean enabled) {
318 this.enableTracing = enabled;
319 }
320
Kun Zhang942f4c92015-09-04 17:21:44 -0700321 @Override
Kun Zhangd17a7b52017-01-10 15:30:12 -0800322 public ManagedChannel build() {
Eric Anderson0a8d7612017-05-23 11:08:34 -0700323 return new ManagedChannelImpl(
324 this,
325 buildTransportFactory(),
326 // TODO(carl-mastrangelo): Allow clients to pass this in
327 new ExponentialBackoffPolicy.Provider(),
328 SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE),
329 SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),
330 GrpcUtil.STOPWATCH_SUPPLIER,
331 getEffectiveInterceptors());
332 }
Kun Zhang903197b2017-04-07 11:03:24 -0700333
Eric Anderson0a8d7612017-05-23 11:08:34 -0700334 private List<ClientInterceptor> getEffectiveInterceptors() {
Kun Zhang49bde542017-04-25 13:53:29 -0700335 List<ClientInterceptor> effectiveInterceptors =
336 new ArrayList<ClientInterceptor>(this.interceptors);
Kun Zhangbe74e972017-04-26 10:50:55 -0700337 if (recordsStats()) {
Kun Zhang903197b2017-04-07 11:03:24 -0700338 StatsContextFactory statsCtxFactory =
339 this.statsFactory != null ? this.statsFactory : Stats.getStatsContextFactory();
340 if (statsCtxFactory != null) {
Kun Zhang49bde542017-04-25 13:53:29 -0700341 CensusStatsModule censusStats =
Kun Zhangbe74e972017-04-26 10:50:55 -0700342 new CensusStatsModule(
343 statsCtxFactory, GrpcUtil.STOPWATCH_SUPPLIER, enableStatsTagPropagation);
Kun Zhang903197b2017-04-07 11:03:24 -0700344 // First interceptor runs last (see ClientInterceptors.intercept()), so that no
345 // other interceptor can override the tracer factory we set in CallOptions.
Kun Zhang49bde542017-04-25 13:53:29 -0700346 effectiveInterceptors.add(0, censusStats.getClientInterceptor());
Kun Zhang903197b2017-04-07 11:03:24 -0700347 }
348 }
Kun Zhangbe74e972017-04-26 10:50:55 -0700349 if (enableTracing) {
Kun Zhang49bde542017-04-25 13:53:29 -0700350 CensusTracingModule censusTracing =
351 new CensusTracingModule(Tracing.getTracer(), Tracing.getBinaryPropagationHandler());
352 effectiveInterceptors.add(0, censusTracing.getClientInterceptor());
353 }
Eric Anderson0a8d7612017-05-23 11:08:34 -0700354 return effectiveInterceptors;
zhangkun8d6d12e2014-10-15 13:04:19 -0700355 }
356
357 /**
Kun Zhangedd57c92015-10-27 12:47:29 -0700358 * Subclasses should override this method to provide the {@link ClientTransportFactory}
359 * appropriate for this channel. This method is meant for Transport implementors and should not
360 * be used by normal users.
zhangkun8d6d12e2014-10-15 13:04:19 -0700361 */
nmittler777e9282015-08-19 10:01:52 -0700362 protected abstract ClientTransportFactory buildTransportFactory();
Kun Zhang942f4c92015-09-04 17:21:44 -0700363
Kun Zhangedd57c92015-10-27 12:47:29 -0700364 /**
365 * Subclasses can override this method to provide additional parameters to {@link
366 * NameResolver.Factory#newNameResolver}. The default implementation returns {@link
Carl Mastrangelo82a79d82015-12-07 14:40:11 -0800367 * Attributes#EMPTY}.
Kun Zhangedd57c92015-10-27 12:47:29 -0700368 */
369 protected Attributes getNameResolverParams() {
370 return Attributes.EMPTY;
371 }
372
zpencer726c23b2017-06-16 18:54:47 -0700373 /**
374 * Returns a {@link NameResolver.Factory} for the channel.
375 */
376 NameResolver.Factory getNameResolverFactory() {
377 if (authorityOverride == null) {
378 return nameResolverFactory;
379 } else {
380 return new OverrideAuthorityNameResolverFactory(nameResolverFactory, authorityOverride);
381 }
382 }
383
Kun Zhang942f4c92015-09-04 17:21:44 -0700384 private static class DirectAddressNameResolverFactory extends NameResolver.Factory {
385 final SocketAddress address;
386 final String authority;
387
388 DirectAddressNameResolverFactory(SocketAddress address, String authority) {
389 this.address = address;
390 this.authority = authority;
391 }
392
393 @Override
Kun Zhangedd57c92015-10-27 12:47:29 -0700394 public NameResolver newNameResolver(URI notUsedUri, Attributes params) {
Kun Zhang942f4c92015-09-04 17:21:44 -0700395 return new NameResolver() {
396 @Override
397 public String getServiceAuthority() {
398 return authority;
399 }
400
401 @Override
402 public void start(final Listener listener) {
Kun Zhang418d52d2017-03-22 18:29:31 -0700403 listener.onAddresses(
404 Collections.singletonList(new EquivalentAddressGroup(address)),
Kun Zhang942f4c92015-09-04 17:21:44 -0700405 Attributes.EMPTY);
406 }
407
408 @Override
409 public void shutdown() {}
410 };
411 }
Kun Zhang16247152015-12-08 17:52:05 -0800412
413 @Override
414 public String getDefaultScheme() {
415 return DIRECT_ADDRESS_SCHEME;
416 }
Kun Zhang942f4c92015-09-04 17:21:44 -0700417 }
Carl Mastrangelo84934982017-01-11 12:46:47 -0800418
419 /**
420 * Returns the correctly typed version of the builder.
421 */
422 private T thisT() {
423 @SuppressWarnings("unchecked")
424 T thisT = (T) this;
425 return thisT;
426 }
zhangkun8d6d12e2014-10-15 13:04:19 -0700427}