1 /* 2 * Copyright 2020 The gRPC Authors 3 * 4 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * 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. 15 */ 16 17 package io.grpc.internal; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 21 import com.google.common.annotations.VisibleForTesting; 22 import com.google.common.base.Preconditions; 23 import com.google.common.util.concurrent.MoreExecutors; 24 import com.google.errorprone.annotations.DoNotCall; 25 import io.grpc.Attributes; 26 import io.grpc.BinaryLog; 27 import io.grpc.CallCredentials; 28 import io.grpc.ChannelCredentials; 29 import io.grpc.ClientInterceptor; 30 import io.grpc.CompressorRegistry; 31 import io.grpc.DecompressorRegistry; 32 import io.grpc.EquivalentAddressGroup; 33 import io.grpc.InternalChannelz; 34 import io.grpc.InternalGlobalInterceptors; 35 import io.grpc.ManagedChannel; 36 import io.grpc.ManagedChannelBuilder; 37 import io.grpc.NameResolver; 38 import io.grpc.NameResolverRegistry; 39 import io.grpc.ProxyDetector; 40 import java.lang.reflect.InvocationTargetException; 41 import java.lang.reflect.Method; 42 import java.net.SocketAddress; 43 import java.net.URI; 44 import java.net.URISyntaxException; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.LinkedHashMap; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.concurrent.Executor; 52 import java.util.concurrent.TimeUnit; 53 import java.util.logging.Level; 54 import java.util.logging.Logger; 55 import javax.annotation.Nullable; 56 57 /** 58 * Default managed channel builder, for usage in Transport implementations. 59 */ 60 public final class ManagedChannelImplBuilder 61 extends ManagedChannelBuilder<ManagedChannelImplBuilder> { 62 private static final String DIRECT_ADDRESS_SCHEME = "directaddress"; 63 64 private static final Logger log = Logger.getLogger(ManagedChannelImplBuilder.class.getName()); 65 66 @DoNotCall("ClientTransportFactoryBuilder is required, use a constructor") forAddress(String name, int port)67 public static ManagedChannelBuilder<?> forAddress(String name, int port) { 68 throw new UnsupportedOperationException( 69 "ClientTransportFactoryBuilder is required, use a constructor"); 70 } 71 72 @DoNotCall("ClientTransportFactoryBuilder is required, use a constructor") forTarget(String target)73 public static ManagedChannelBuilder<?> forTarget(String target) { 74 throw new UnsupportedOperationException( 75 "ClientTransportFactoryBuilder is required, use a constructor"); 76 } 77 78 /** 79 * An idle timeout larger than this would disable idle mode. 80 */ 81 @VisibleForTesting 82 static final long IDLE_MODE_MAX_TIMEOUT_DAYS = 30; 83 84 /** 85 * The default idle timeout. 86 */ 87 @VisibleForTesting 88 static final long IDLE_MODE_DEFAULT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(30); 89 90 /** 91 * An idle timeout smaller than this would be capped to it. 92 */ 93 static final long IDLE_MODE_MIN_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(1); 94 95 private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL = 96 SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR); 97 98 private static final DecompressorRegistry DEFAULT_DECOMPRESSOR_REGISTRY = 99 DecompressorRegistry.getDefaultInstance(); 100 101 private static final CompressorRegistry DEFAULT_COMPRESSOR_REGISTRY = 102 CompressorRegistry.getDefaultInstance(); 103 104 private static final long DEFAULT_RETRY_BUFFER_SIZE_IN_BYTES = 1L << 24; // 16M 105 private static final long DEFAULT_PER_RPC_BUFFER_LIMIT_IN_BYTES = 1L << 20; // 1M 106 107 ObjectPool<? extends Executor> executorPool = DEFAULT_EXECUTOR_POOL; 108 109 ObjectPool<? extends Executor> offloadExecutorPool = DEFAULT_EXECUTOR_POOL; 110 111 private final List<ClientInterceptor> interceptors = new ArrayList<>(); 112 final NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry(); 113 114 // Access via getter, which may perform authority override as needed 115 NameResolver.Factory nameResolverFactory = nameResolverRegistry.asFactory(); 116 117 final String target; 118 @Nullable 119 final ChannelCredentials channelCredentials; 120 @Nullable 121 final CallCredentials callCredentials; 122 123 @Nullable 124 private final SocketAddress directServerAddress; 125 126 @Nullable 127 String userAgent; 128 129 @Nullable 130 String authorityOverride; 131 132 String defaultLbPolicy = GrpcUtil.DEFAULT_LB_POLICY; 133 134 boolean fullStreamDecompression; 135 136 DecompressorRegistry decompressorRegistry = DEFAULT_DECOMPRESSOR_REGISTRY; 137 138 CompressorRegistry compressorRegistry = DEFAULT_COMPRESSOR_REGISTRY; 139 140 long idleTimeoutMillis = IDLE_MODE_DEFAULT_TIMEOUT_MILLIS; 141 142 int maxRetryAttempts = 5; 143 int maxHedgedAttempts = 5; 144 long retryBufferSize = DEFAULT_RETRY_BUFFER_SIZE_IN_BYTES; 145 long perRpcBufferLimit = DEFAULT_PER_RPC_BUFFER_LIMIT_IN_BYTES; 146 boolean retryEnabled = true; 147 148 InternalChannelz channelz = InternalChannelz.instance(); 149 int maxTraceEvents; 150 151 @Nullable 152 Map<String, ?> defaultServiceConfig; 153 boolean lookUpServiceConfig = true; 154 155 @Nullable 156 BinaryLog binlog; 157 158 @Nullable 159 ProxyDetector proxyDetector; 160 161 private boolean authorityCheckerDisabled; 162 private boolean statsEnabled = true; 163 private boolean recordStartedRpcs = true; 164 private boolean recordFinishedRpcs = true; 165 private boolean recordRealTimeMetrics = false; 166 private boolean recordRetryMetrics = true; 167 private boolean tracingEnabled = true; 168 169 /** 170 * An interface for Transport implementors to provide the {@link ClientTransportFactory} 171 * appropriate for the channel. 172 */ 173 public interface ClientTransportFactoryBuilder { buildClientTransportFactory()174 ClientTransportFactory buildClientTransportFactory(); 175 } 176 177 /** 178 * Convenience ClientTransportFactoryBuilder, throws UnsupportedOperationException(). 179 */ 180 public static class UnsupportedClientTransportFactoryBuilder implements 181 ClientTransportFactoryBuilder { 182 @Override buildClientTransportFactory()183 public ClientTransportFactory buildClientTransportFactory() { 184 throw new UnsupportedOperationException(); 185 } 186 } 187 188 /** 189 * An interface for Transport implementors to provide a default port to {@link 190 * io.grpc.NameResolver} for use in cases where the target string doesn't include a port. The 191 * default implementation returns {@link GrpcUtil#DEFAULT_PORT_SSL}. 192 */ 193 public interface ChannelBuilderDefaultPortProvider { getDefaultPort()194 int getDefaultPort(); 195 } 196 197 /** 198 * Default implementation of {@link ChannelBuilderDefaultPortProvider} that returns a fixed port. 199 */ 200 public static final class FixedPortProvider implements ChannelBuilderDefaultPortProvider { 201 private final int port; 202 FixedPortProvider(int port)203 public FixedPortProvider(int port) { 204 this.port = port; 205 } 206 207 @Override getDefaultPort()208 public int getDefaultPort() { 209 return port; 210 } 211 } 212 213 private static final class ManagedChannelDefaultPortProvider implements 214 ChannelBuilderDefaultPortProvider { 215 @Override getDefaultPort()216 public int getDefaultPort() { 217 return GrpcUtil.DEFAULT_PORT_SSL; 218 } 219 } 220 221 private final ClientTransportFactoryBuilder clientTransportFactoryBuilder; 222 private final ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider; 223 224 /** 225 * Creates a new managed channel builder with a target string, which can be either a valid {@link 226 * io.grpc.NameResolver}-compliant URI, or an authority string. Transport implementors must 227 * provide client transport factory builder, and may set custom channel default port provider. 228 */ ManagedChannelImplBuilder(String target, ClientTransportFactoryBuilder clientTransportFactoryBuilder, @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider)229 public ManagedChannelImplBuilder(String target, 230 ClientTransportFactoryBuilder clientTransportFactoryBuilder, 231 @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { 232 this(target, null, null, clientTransportFactoryBuilder, channelBuilderDefaultPortProvider); 233 } 234 235 /** 236 * Creates a new managed channel builder with a target string, which can be either a valid {@link 237 * io.grpc.NameResolver}-compliant URI, or an authority string. Transport implementors must 238 * provide client transport factory builder, and may set custom channel default port provider. 239 * 240 * @param channelCreds The ChannelCredentials provided by the user. These may be used when 241 * creating derivative channels. 242 */ ManagedChannelImplBuilder( String target, @Nullable ChannelCredentials channelCreds, @Nullable CallCredentials callCreds, ClientTransportFactoryBuilder clientTransportFactoryBuilder, @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider)243 public ManagedChannelImplBuilder( 244 String target, @Nullable ChannelCredentials channelCreds, @Nullable CallCredentials callCreds, 245 ClientTransportFactoryBuilder clientTransportFactoryBuilder, 246 @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { 247 this.target = Preconditions.checkNotNull(target, "target"); 248 this.channelCredentials = channelCreds; 249 this.callCredentials = callCreds; 250 this.clientTransportFactoryBuilder = Preconditions 251 .checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder"); 252 this.directServerAddress = null; 253 254 if (channelBuilderDefaultPortProvider != null) { 255 this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider; 256 } else { 257 this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider(); 258 } 259 } 260 261 /** 262 * Returns a target string for the SocketAddress. It is only used as a placeholder, because 263 * DirectAddressNameResolverFactory will not actually try to use it. However, it must be a valid 264 * URI. 265 */ 266 @VisibleForTesting makeTargetStringForDirectAddress(SocketAddress address)267 static String makeTargetStringForDirectAddress(SocketAddress address) { 268 try { 269 return new URI(DIRECT_ADDRESS_SCHEME, "", "/" + address, null).toString(); 270 } catch (URISyntaxException e) { 271 // It should not happen. 272 throw new RuntimeException(e); 273 } 274 } 275 276 /** 277 * Creates a new managed channel builder with the given server address, authority string of the 278 * channel. Transport implementors must provide client transport factory builder, and may set 279 * custom channel default port provider. 280 */ ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority, ClientTransportFactoryBuilder clientTransportFactoryBuilder, @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider)281 public ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority, 282 ClientTransportFactoryBuilder clientTransportFactoryBuilder, 283 @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { 284 this(directServerAddress, authority, null, null, clientTransportFactoryBuilder, 285 channelBuilderDefaultPortProvider); 286 } 287 288 /** 289 * Creates a new managed channel builder with the given server address, authority string of the 290 * channel. Transport implementors must provide client transport factory builder, and may set 291 * custom channel default port provider. 292 * 293 * @param channelCreds The ChannelCredentials provided by the user. These may be used when 294 * creating derivative channels. 295 */ ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority, @Nullable ChannelCredentials channelCreds, @Nullable CallCredentials callCreds, ClientTransportFactoryBuilder clientTransportFactoryBuilder, @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider)296 public ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority, 297 @Nullable ChannelCredentials channelCreds, @Nullable CallCredentials callCreds, 298 ClientTransportFactoryBuilder clientTransportFactoryBuilder, 299 @Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) { 300 this.target = makeTargetStringForDirectAddress(directServerAddress); 301 this.channelCredentials = channelCreds; 302 this.callCredentials = callCreds; 303 this.clientTransportFactoryBuilder = Preconditions 304 .checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder"); 305 this.directServerAddress = directServerAddress; 306 this.nameResolverFactory = new DirectAddressNameResolverFactory(directServerAddress, authority); 307 308 if (channelBuilderDefaultPortProvider != null) { 309 this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider; 310 } else { 311 this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider(); 312 } 313 } 314 315 @Override directExecutor()316 public ManagedChannelImplBuilder directExecutor() { 317 return executor(MoreExecutors.directExecutor()); 318 } 319 320 @Override executor(Executor executor)321 public ManagedChannelImplBuilder executor(Executor executor) { 322 if (executor != null) { 323 this.executorPool = new FixedObjectPool<>(executor); 324 } else { 325 this.executorPool = DEFAULT_EXECUTOR_POOL; 326 } 327 return this; 328 } 329 330 @Override offloadExecutor(Executor executor)331 public ManagedChannelImplBuilder offloadExecutor(Executor executor) { 332 if (executor != null) { 333 this.offloadExecutorPool = new FixedObjectPool<>(executor); 334 } else { 335 this.offloadExecutorPool = DEFAULT_EXECUTOR_POOL; 336 } 337 return this; 338 } 339 340 @Override intercept(List<ClientInterceptor> interceptors)341 public ManagedChannelImplBuilder intercept(List<ClientInterceptor> interceptors) { 342 this.interceptors.addAll(interceptors); 343 return this; 344 } 345 346 @Override intercept(ClientInterceptor... interceptors)347 public ManagedChannelImplBuilder intercept(ClientInterceptor... interceptors) { 348 return intercept(Arrays.asList(interceptors)); 349 } 350 351 @Deprecated 352 @Override nameResolverFactory(NameResolver.Factory resolverFactory)353 public ManagedChannelImplBuilder nameResolverFactory(NameResolver.Factory resolverFactory) { 354 Preconditions.checkState(directServerAddress == null, 355 "directServerAddress is set (%s), which forbids the use of NameResolverFactory", 356 directServerAddress); 357 if (resolverFactory != null) { 358 this.nameResolverFactory = resolverFactory; 359 } else { 360 this.nameResolverFactory = nameResolverRegistry.asFactory(); 361 } 362 return this; 363 } 364 365 @Override defaultLoadBalancingPolicy(String policy)366 public ManagedChannelImplBuilder defaultLoadBalancingPolicy(String policy) { 367 Preconditions.checkState(directServerAddress == null, 368 "directServerAddress is set (%s), which forbids the use of load-balancing policy", 369 directServerAddress); 370 Preconditions.checkArgument(policy != null, "policy cannot be null"); 371 this.defaultLbPolicy = policy; 372 return this; 373 } 374 375 @Override enableFullStreamDecompression()376 public ManagedChannelImplBuilder enableFullStreamDecompression() { 377 this.fullStreamDecompression = true; 378 return this; 379 } 380 381 @Override decompressorRegistry(DecompressorRegistry registry)382 public ManagedChannelImplBuilder decompressorRegistry(DecompressorRegistry registry) { 383 if (registry != null) { 384 this.decompressorRegistry = registry; 385 } else { 386 this.decompressorRegistry = DEFAULT_DECOMPRESSOR_REGISTRY; 387 } 388 return this; 389 } 390 391 @Override compressorRegistry(CompressorRegistry registry)392 public ManagedChannelImplBuilder compressorRegistry(CompressorRegistry registry) { 393 if (registry != null) { 394 this.compressorRegistry = registry; 395 } else { 396 this.compressorRegistry = DEFAULT_COMPRESSOR_REGISTRY; 397 } 398 return this; 399 } 400 401 @Override userAgent(@ullable String userAgent)402 public ManagedChannelImplBuilder userAgent(@Nullable String userAgent) { 403 this.userAgent = userAgent; 404 return this; 405 } 406 407 @Override overrideAuthority(String authority)408 public ManagedChannelImplBuilder overrideAuthority(String authority) { 409 this.authorityOverride = checkAuthority(authority); 410 return this; 411 } 412 413 @Override idleTimeout(long value, TimeUnit unit)414 public ManagedChannelImplBuilder idleTimeout(long value, TimeUnit unit) { 415 checkArgument(value > 0, "idle timeout is %s, but must be positive", value); 416 // We convert to the largest unit to avoid overflow 417 if (unit.toDays(value) >= IDLE_MODE_MAX_TIMEOUT_DAYS) { 418 // This disables idle mode 419 this.idleTimeoutMillis = ManagedChannelImpl.IDLE_TIMEOUT_MILLIS_DISABLE; 420 } else { 421 this.idleTimeoutMillis = Math.max(unit.toMillis(value), IDLE_MODE_MIN_TIMEOUT_MILLIS); 422 } 423 return this; 424 } 425 426 @Override maxRetryAttempts(int maxRetryAttempts)427 public ManagedChannelImplBuilder maxRetryAttempts(int maxRetryAttempts) { 428 this.maxRetryAttempts = maxRetryAttempts; 429 return this; 430 } 431 432 @Override maxHedgedAttempts(int maxHedgedAttempts)433 public ManagedChannelImplBuilder maxHedgedAttempts(int maxHedgedAttempts) { 434 this.maxHedgedAttempts = maxHedgedAttempts; 435 return this; 436 } 437 438 @Override retryBufferSize(long bytes)439 public ManagedChannelImplBuilder retryBufferSize(long bytes) { 440 checkArgument(bytes > 0L, "retry buffer size must be positive"); 441 retryBufferSize = bytes; 442 return this; 443 } 444 445 @Override perRpcBufferLimit(long bytes)446 public ManagedChannelImplBuilder perRpcBufferLimit(long bytes) { 447 checkArgument(bytes > 0L, "per RPC buffer limit must be positive"); 448 perRpcBufferLimit = bytes; 449 return this; 450 } 451 452 @Override disableRetry()453 public ManagedChannelImplBuilder disableRetry() { 454 retryEnabled = false; 455 return this; 456 } 457 458 @Override enableRetry()459 public ManagedChannelImplBuilder enableRetry() { 460 retryEnabled = true; 461 return this; 462 } 463 464 @Override setBinaryLog(BinaryLog binlog)465 public ManagedChannelImplBuilder setBinaryLog(BinaryLog binlog) { 466 this.binlog = binlog; 467 return this; 468 } 469 470 @Override maxTraceEvents(int maxTraceEvents)471 public ManagedChannelImplBuilder maxTraceEvents(int maxTraceEvents) { 472 checkArgument(maxTraceEvents >= 0, "maxTraceEvents must be non-negative"); 473 this.maxTraceEvents = maxTraceEvents; 474 return this; 475 } 476 477 @Override proxyDetector(@ullable ProxyDetector proxyDetector)478 public ManagedChannelImplBuilder proxyDetector(@Nullable ProxyDetector proxyDetector) { 479 this.proxyDetector = proxyDetector; 480 return this; 481 } 482 483 @Override defaultServiceConfig(@ullable Map<String, ?> serviceConfig)484 public ManagedChannelImplBuilder defaultServiceConfig(@Nullable Map<String, ?> serviceConfig) { 485 // TODO(notcarl): use real parsing 486 defaultServiceConfig = checkMapEntryTypes(serviceConfig); 487 return this; 488 } 489 490 @Nullable checkMapEntryTypes(@ullable Map<?, ?> map)491 private static Map<String, ?> checkMapEntryTypes(@Nullable Map<?, ?> map) { 492 if (map == null) { 493 return null; 494 } 495 // Not using ImmutableMap.Builder because of extra guava dependency for Android. 496 Map<String, Object> parsedMap = new LinkedHashMap<>(); 497 for (Map.Entry<?, ?> entry : map.entrySet()) { 498 checkArgument( 499 entry.getKey() instanceof String, 500 "The key of the entry '%s' is not of String type", entry); 501 502 String key = (String) entry.getKey(); 503 Object value = entry.getValue(); 504 if (value == null) { 505 parsedMap.put(key, null); 506 } else if (value instanceof Map) { 507 parsedMap.put(key, checkMapEntryTypes((Map<?, ?>) value)); 508 } else if (value instanceof List) { 509 parsedMap.put(key, checkListEntryTypes((List<?>) value)); 510 } else if (value instanceof String) { 511 parsedMap.put(key, value); 512 } else if (value instanceof Double) { 513 parsedMap.put(key, value); 514 } else if (value instanceof Boolean) { 515 parsedMap.put(key, value); 516 } else { 517 throw new IllegalArgumentException( 518 "The value of the map entry '" + entry + "' is of type '" + value.getClass() 519 + "', which is not supported"); 520 } 521 } 522 return Collections.unmodifiableMap(parsedMap); 523 } 524 checkListEntryTypes(List<?> list)525 private static List<?> checkListEntryTypes(List<?> list) { 526 List<Object> parsedList = new ArrayList<>(list.size()); 527 for (Object value : list) { 528 if (value == null) { 529 parsedList.add(null); 530 } else if (value instanceof Map) { 531 parsedList.add(checkMapEntryTypes((Map<?, ?>) value)); 532 } else if (value instanceof List) { 533 parsedList.add(checkListEntryTypes((List<?>) value)); 534 } else if (value instanceof String) { 535 parsedList.add(value); 536 } else if (value instanceof Double) { 537 parsedList.add(value); 538 } else if (value instanceof Boolean) { 539 parsedList.add(value); 540 } else { 541 throw new IllegalArgumentException( 542 "The entry '" + value + "' is of type '" + value.getClass() 543 + "', which is not supported"); 544 } 545 } 546 return Collections.unmodifiableList(parsedList); 547 } 548 549 @Override disableServiceConfigLookUp()550 public ManagedChannelImplBuilder disableServiceConfigLookUp() { 551 this.lookUpServiceConfig = false; 552 return this; 553 } 554 555 /** 556 * Disable or enable stats features. Enabled by default. 557 * 558 * <p>For the current release, calling {@code setStatsEnabled(true)} may have a side effect that 559 * disables retry. 560 */ setStatsEnabled(boolean value)561 public void setStatsEnabled(boolean value) { 562 statsEnabled = value; 563 } 564 565 /** 566 * Disable or enable stats recording for RPC upstarts. Effective only if {@link 567 * #setStatsEnabled} is set to true. Enabled by default. 568 */ setStatsRecordStartedRpcs(boolean value)569 public void setStatsRecordStartedRpcs(boolean value) { 570 recordStartedRpcs = value; 571 } 572 573 /** 574 * Disable or enable stats recording for RPC completions. Effective only if {@link 575 * #setStatsEnabled} is set to true. Enabled by default. 576 */ setStatsRecordFinishedRpcs(boolean value)577 public void setStatsRecordFinishedRpcs(boolean value) { 578 recordFinishedRpcs = value; 579 } 580 581 /** 582 * Disable or enable real-time metrics recording. Effective only if {@link #setStatsEnabled} is 583 * set to true. Disabled by default. 584 */ setStatsRecordRealTimeMetrics(boolean value)585 public void setStatsRecordRealTimeMetrics(boolean value) { 586 recordRealTimeMetrics = value; 587 } 588 setStatsRecordRetryMetrics(boolean value)589 public void setStatsRecordRetryMetrics(boolean value) { 590 recordRetryMetrics = value; 591 } 592 593 /** 594 * Disable or enable tracing features. Enabled by default. 595 */ setTracingEnabled(boolean value)596 public void setTracingEnabled(boolean value) { 597 tracingEnabled = value; 598 } 599 600 /** 601 * Verifies the authority is valid. 602 */ 603 @VisibleForTesting checkAuthority(String authority)604 String checkAuthority(String authority) { 605 if (authorityCheckerDisabled) { 606 return authority; 607 } 608 return GrpcUtil.checkAuthority(authority); 609 } 610 611 /** Disable the check whether the authority is valid. */ disableCheckAuthority()612 public ManagedChannelImplBuilder disableCheckAuthority() { 613 authorityCheckerDisabled = true; 614 return this; 615 } 616 617 /** Enable previously disabled authority check. */ enableCheckAuthority()618 public ManagedChannelImplBuilder enableCheckAuthority() { 619 authorityCheckerDisabled = false; 620 return this; 621 } 622 623 @Override build()624 public ManagedChannel build() { 625 return new ManagedChannelOrphanWrapper(new ManagedChannelImpl( 626 this, 627 clientTransportFactoryBuilder.buildClientTransportFactory(), 628 new ExponentialBackoffPolicy.Provider(), 629 SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR), 630 GrpcUtil.STOPWATCH_SUPPLIER, 631 getEffectiveInterceptors(), 632 TimeProvider.SYSTEM_TIME_PROVIDER)); 633 } 634 635 // Temporarily disable retry when stats or tracing is enabled to avoid breakage, until we know 636 // what should be the desired behavior for retry + stats/tracing. 637 // TODO(zdapeng): FIX IT 638 @VisibleForTesting getEffectiveInterceptors()639 List<ClientInterceptor> getEffectiveInterceptors() { 640 List<ClientInterceptor> effectiveInterceptors = new ArrayList<>(this.interceptors); 641 boolean isGlobalInterceptorsSet = false; 642 List<ClientInterceptor> globalClientInterceptors = 643 InternalGlobalInterceptors.getClientInterceptors(); 644 if (globalClientInterceptors != null) { 645 effectiveInterceptors.addAll(globalClientInterceptors); 646 isGlobalInterceptorsSet = true; 647 } 648 if (!isGlobalInterceptorsSet && statsEnabled) { 649 ClientInterceptor statsInterceptor = null; 650 try { 651 Class<?> censusStatsAccessor = 652 Class.forName("io.grpc.census.InternalCensusStatsAccessor"); 653 Method getClientInterceptorMethod = 654 censusStatsAccessor.getDeclaredMethod( 655 "getClientInterceptor", 656 boolean.class, 657 boolean.class, 658 boolean.class, 659 boolean.class); 660 statsInterceptor = 661 (ClientInterceptor) getClientInterceptorMethod 662 .invoke( 663 null, 664 recordStartedRpcs, 665 recordFinishedRpcs, 666 recordRealTimeMetrics, 667 recordRetryMetrics); 668 } catch (ClassNotFoundException e) { 669 // Replace these separate catch statements with multicatch when Android min-API >= 19 670 log.log(Level.FINE, "Unable to apply census stats", e); 671 } catch (NoSuchMethodException e) { 672 log.log(Level.FINE, "Unable to apply census stats", e); 673 } catch (IllegalAccessException e) { 674 log.log(Level.FINE, "Unable to apply census stats", e); 675 } catch (InvocationTargetException e) { 676 log.log(Level.FINE, "Unable to apply census stats", e); 677 } 678 if (statsInterceptor != null) { 679 // First interceptor runs last (see ClientInterceptors.intercept()), so that no 680 // other interceptor can override the tracer factory we set in CallOptions. 681 effectiveInterceptors.add(0, statsInterceptor); 682 } 683 } 684 if (!isGlobalInterceptorsSet && tracingEnabled) { 685 ClientInterceptor tracingInterceptor = null; 686 try { 687 Class<?> censusTracingAccessor = 688 Class.forName("io.grpc.census.InternalCensusTracingAccessor"); 689 Method getClientInterceptroMethod = 690 censusTracingAccessor.getDeclaredMethod("getClientInterceptor"); 691 tracingInterceptor = (ClientInterceptor) getClientInterceptroMethod.invoke(null); 692 } catch (ClassNotFoundException e) { 693 // Replace these separate catch statements with multicatch when Android min-API >= 19 694 log.log(Level.FINE, "Unable to apply census stats", e); 695 } catch (NoSuchMethodException e) { 696 log.log(Level.FINE, "Unable to apply census stats", e); 697 } catch (IllegalAccessException e) { 698 log.log(Level.FINE, "Unable to apply census stats", e); 699 } catch (InvocationTargetException e) { 700 log.log(Level.FINE, "Unable to apply census stats", e); 701 } 702 if (tracingInterceptor != null) { 703 effectiveInterceptors.add(0, tracingInterceptor); 704 } 705 } 706 return effectiveInterceptors; 707 } 708 709 /** 710 * Returns a default port to {@link NameResolver} for use in cases where the target string doesn't 711 * include a port. The default implementation returns {@link GrpcUtil#DEFAULT_PORT_SSL}. 712 */ getDefaultPort()713 int getDefaultPort() { 714 return channelBuilderDefaultPortProvider.getDefaultPort(); 715 } 716 717 private static class DirectAddressNameResolverFactory extends NameResolver.Factory { 718 final SocketAddress address; 719 final String authority; 720 DirectAddressNameResolverFactory(SocketAddress address, String authority)721 DirectAddressNameResolverFactory(SocketAddress address, String authority) { 722 this.address = address; 723 this.authority = authority; 724 } 725 726 @Override newNameResolver(URI notUsedUri, NameResolver.Args args)727 public NameResolver newNameResolver(URI notUsedUri, NameResolver.Args args) { 728 return new NameResolver() { 729 @Override 730 public String getServiceAuthority() { 731 return authority; 732 } 733 734 @Override 735 public void start(Listener2 listener) { 736 listener.onResult( 737 ResolutionResult.newBuilder() 738 .setAddresses(Collections.singletonList(new EquivalentAddressGroup(address))) 739 .setAttributes(Attributes.EMPTY) 740 .build()); 741 } 742 743 @Override 744 public void shutdown() {} 745 }; 746 } 747 748 @Override getDefaultScheme()749 public String getDefaultScheme() { 750 return DIRECT_ADDRESS_SCHEME; 751 } 752 } 753 754 /** 755 * Returns the internal offload executor pool for offloading tasks. 756 */ 757 public ObjectPool<? extends Executor> getOffloadExecutorPool() { 758 return this.offloadExecutorPool; 759 } 760 } 761