28
28
import java .lang .annotation .RetentionPolicy ;
29
29
import java .net .URI ;
30
30
import java .util .Collections ;
31
+ import java .util .IdentityHashMap ;
31
32
import java .util .List ;
32
33
import java .util .Map ;
33
34
import java .util .concurrent .Executor ;
34
35
import java .util .concurrent .ScheduledExecutorService ;
35
36
import javax .annotation .Nullable ;
37
+ import javax .annotation .concurrent .Immutable ;
36
38
import javax .annotation .concurrent .ThreadSafe ;
37
39
38
40
/**
@@ -276,7 +278,12 @@ public Status onResult2(ResolutionResult resolutionResult) {
276
278
/**
277
279
* Information that a {@link Factory} uses to create a {@link NameResolver}.
278
280
*
279
- * <p>Note this class doesn't override neither {@code equals()} nor {@code hashCode()}.
281
+ * <p>Args applicable to all {@link NameResolver}s are defined here using ordinary setters and
282
+ * getters. This container can also hold externally-defined "custom" args that aren't so widely
283
+ * useful or that would be inappropriate dependencies for this low level API. See {@link
284
+ * Args#getArg} for more.
285
+ *
286
+ * <p>Note this class overrides neither {@code equals()} nor {@code hashCode()}.
280
287
*
281
288
* @since 1.21.0
282
289
*/
@@ -291,26 +298,20 @@ public static final class Args {
291
298
@ Nullable private final Executor executor ;
292
299
@ Nullable private final String overrideAuthority ;
293
300
@ Nullable private final MetricRecorder metricRecorder ;
301
+ @ Nullable private final IdentityHashMap <Key <?>, Object > customArgs ;
294
302
295
- private Args (
296
- Integer defaultPort ,
297
- ProxyDetector proxyDetector ,
298
- SynchronizationContext syncContext ,
299
- ServiceConfigParser serviceConfigParser ,
300
- @ Nullable ScheduledExecutorService scheduledExecutorService ,
301
- @ Nullable ChannelLogger channelLogger ,
302
- @ Nullable Executor executor ,
303
- @ Nullable String overrideAuthority ,
304
- @ Nullable MetricRecorder metricRecorder ) {
305
- this .defaultPort = checkNotNull (defaultPort , "defaultPort not set" );
306
- this .proxyDetector = checkNotNull (proxyDetector , "proxyDetector not set" );
307
- this .syncContext = checkNotNull (syncContext , "syncContext not set" );
308
- this .serviceConfigParser = checkNotNull (serviceConfigParser , "serviceConfigParser not set" );
309
- this .scheduledExecutorService = scheduledExecutorService ;
310
- this .channelLogger = channelLogger ;
311
- this .executor = executor ;
312
- this .overrideAuthority = overrideAuthority ;
313
- this .metricRecorder = metricRecorder ;
303
+ private Args (Builder builder ) {
304
+ this .defaultPort = checkNotNull (builder .defaultPort , "defaultPort not set" );
305
+ this .proxyDetector = checkNotNull (builder .proxyDetector , "proxyDetector not set" );
306
+ this .syncContext = checkNotNull (builder .syncContext , "syncContext not set" );
307
+ this .serviceConfigParser =
308
+ checkNotNull (builder .serviceConfigParser , "serviceConfigParser not set" );
309
+ this .scheduledExecutorService = builder .scheduledExecutorService ;
310
+ this .channelLogger = builder .channelLogger ;
311
+ this .executor = builder .executor ;
312
+ this .overrideAuthority = builder .overrideAuthority ;
313
+ this .metricRecorder = builder .metricRecorder ;
314
+ this .customArgs = cloneCustomArgs (builder .customArgs );
314
315
}
315
316
316
317
/**
@@ -319,6 +320,7 @@ private Args(
319
320
*
320
321
* @since 1.21.0
321
322
*/
323
+ // <p>TODO: Only meaningful for InetSocketAddress producers. Make this a custom arg?
322
324
public int getDefaultPort () {
323
325
return defaultPort ;
324
326
}
@@ -371,6 +373,30 @@ public ServiceConfigParser getServiceConfigParser() {
371
373
return serviceConfigParser ;
372
374
}
373
375
376
+ /**
377
+ * Returns the value of a custom arg named 'key', or {@code null} if it's not set.
378
+ *
379
+ * <p>While ordinary {@link Args} should be universally useful and meaningful, custom arguments
380
+ * can apply just to resolvers of a certain URI scheme, just to resolvers producing a particular
381
+ * type of {@link java.net.SocketAddress}, or even an individual {@link NameResolver} subclass.
382
+ * Custom args are identified by an instance of {@link Args.Key} which should be a constant
383
+ * defined in a java package and class appropriate for the argument's scope.
384
+ *
385
+ * <p>{@link Args} are normally reserved for information in *support* of name resolution, not
386
+ * the name to be resolved itself. However, there are rare cases where all or part of the target
387
+ * name can't be represented by any standard URI scheme or can't be encoded as a String at all.
388
+ * Custom args, in contrast, can hold arbitrary Java types, making them a useful work around in
389
+ * these cases.
390
+ *
391
+ * <p>Custom args can also be used simply to avoid adding inappropriate deps to the low level
392
+ * io.grpc package.
393
+ */
394
+ @ SuppressWarnings ("unchecked" ) // Cast is safe because all put()s go through the setArg() API.
395
+ @ Nullable
396
+ public <T > T getArg (Key <T > key ) {
397
+ return customArgs != null ? (T ) customArgs .get (key ) : null ;
398
+ }
399
+
374
400
/**
375
401
* Returns the {@link ChannelLogger} for the Channel served by this NameResolver.
376
402
*
@@ -424,6 +450,7 @@ public String toString() {
424
450
.add ("proxyDetector" , proxyDetector )
425
451
.add ("syncContext" , syncContext )
426
452
.add ("serviceConfigParser" , serviceConfigParser )
453
+ .add ("customArgs" , customArgs )
427
454
.add ("scheduledExecutorService" , scheduledExecutorService )
428
455
.add ("channelLogger" , channelLogger )
429
456
.add ("executor" , executor )
@@ -448,6 +475,7 @@ public Builder toBuilder() {
448
475
builder .setOffloadExecutor (executor );
449
476
builder .setOverrideAuthority (overrideAuthority );
450
477
builder .setMetricRecorder (metricRecorder );
478
+ builder .customArgs = cloneCustomArgs (customArgs );
451
479
return builder ;
452
480
}
453
481
@@ -475,6 +503,7 @@ public static final class Builder {
475
503
private Executor executor ;
476
504
private String overrideAuthority ;
477
505
private MetricRecorder metricRecorder ;
506
+ private IdentityHashMap <Key <?>, Object > customArgs ;
478
507
479
508
Builder () {
480
509
}
@@ -561,6 +590,17 @@ public Builder setOverrideAuthority(String authority) {
561
590
return this ;
562
591
}
563
592
593
+ /** See {@link Args#getArg(Key)}. */
594
+ public <T > Builder setArg (Key <T > key , T value ) {
595
+ checkNotNull (key , "key" );
596
+ checkNotNull (value , "value" );
597
+ if (customArgs == null ) {
598
+ customArgs = new IdentityHashMap <>();
599
+ }
600
+ customArgs .put (key , value );
601
+ return this ;
602
+ }
603
+
564
604
/**
565
605
* See {@link Args#getMetricRecorder()}. This is an optional field.
566
606
*/
@@ -575,11 +615,40 @@ public Builder setMetricRecorder(MetricRecorder metricRecorder) {
575
615
* @since 1.21.0
576
616
*/
577
617
public Args build () {
578
- return
579
- new Args (
580
- defaultPort , proxyDetector , syncContext , serviceConfigParser ,
581
- scheduledExecutorService , channelLogger , executor , overrideAuthority ,
582
- metricRecorder );
618
+ return new Args (this );
619
+ }
620
+ }
621
+
622
+ /**
623
+ * Identifies an externally-defined custom argument that can be stored in {@link Args}.
624
+ *
625
+ * <p>Uses reference equality so keys should be defined as global constants.
626
+ *
627
+ * @param <T> type of values that can be stored under this key
628
+ */
629
+ @ Immutable
630
+ @ SuppressWarnings ("UnusedTypeParameter" )
631
+ public static final class Key <T > {
632
+ private final String debugString ;
633
+
634
+ private Key (String debugString ) {
635
+ this .debugString = debugString ;
636
+ }
637
+
638
+ @ Override
639
+ public String toString () {
640
+ return debugString ;
641
+ }
642
+
643
+ /**
644
+ * Creates a new instance of {@link Key}.
645
+ *
646
+ * @param debugString a string used to describe the key, used for debugging.
647
+ * @param <T> Key type
648
+ * @return a new instance of Key
649
+ */
650
+ public static <T > Key <T > create (String debugString ) {
651
+ return new Key <>(debugString );
583
652
}
584
653
}
585
654
}
@@ -877,4 +946,10 @@ public String toString() {
877
946
}
878
947
}
879
948
}
949
+
950
+ @ Nullable
951
+ private static IdentityHashMap <Args .Key <?>, Object > cloneCustomArgs (
952
+ @ Nullable IdentityHashMap <Args .Key <?>, Object > customArgs ) {
953
+ return customArgs != null ? new IdentityHashMap <>(customArgs ) : null ;
954
+ }
880
955
}
0 commit comments