2020import com .google .common .base .Preconditions ;
2121import java .net .URI ;
2222import java .util .ArrayList ;
23- import java .util .Collections ;
24- import java .util .Comparator ;
23+ import java .util .Iterator ;
2524import java .util .List ;
26- import java .util .ServiceConfigurationError ;
27- import java .util .ServiceLoader ;
2825
2926/**
3027 * Provider of name resolvers for name agnostic consumption.
@@ -41,81 +38,26 @@ public abstract class NameResolverProvider extends NameResolver.Factory {
4138 */
4239 public static final Attributes .Key <Integer > PARAMS_DEFAULT_PORT =
4340 NameResolver .Factory .PARAMS_DEFAULT_PORT ;
44-
45- private static final List <NameResolverProvider > providers
46- = load (NameResolverProvider .class .getClassLoader ());
47- private static final NameResolver .Factory factory = new NameResolverFactory (providers );
48-
4941 @ VisibleForTesting
50- static List <NameResolverProvider > load (ClassLoader classLoader ) {
51- Iterable <NameResolverProvider > candidates ;
52- if (isAndroid ()) {
53- candidates = getCandidatesViaHardCoded ();
54- } else {
55- candidates = getCandidatesViaServiceLoader (classLoader );
56- }
57- List <NameResolverProvider > list = new ArrayList <NameResolverProvider >();
58- for (NameResolverProvider current : candidates ) {
59- if (!current .isAvailable ()) {
60- continue ;
61- }
62- list .add (current );
63- }
64- // Sort descending based on priority.
65- Collections .sort (list , Collections .reverseOrder (new Comparator <NameResolverProvider >() {
66- @ Override
67- public int compare (NameResolverProvider f1 , NameResolverProvider f2 ) {
68- return f1 .priority () - f2 .priority ();
69- }
70- }));
71- return Collections .unmodifiableList (list );
72- }
73-
74- /**
75- * Loads service providers for the {@link NameResolverProvider} service using
76- * {@link ServiceLoader}.
77- */
78- @ VisibleForTesting
79- public static Iterable <NameResolverProvider > getCandidatesViaServiceLoader (
80- ClassLoader classLoader ) {
81- Iterable <NameResolverProvider > i
82- = ServiceLoader .load (NameResolverProvider .class , classLoader );
83- // Attempt to load using the context class loader and ServiceLoader.
84- // This allows frameworks like http://aries.apache.org/modules/spi-fly.html to plug in.
85- if (!i .iterator ().hasNext ()) {
86- i = ServiceLoader .load (NameResolverProvider .class );
87- }
88- return i ;
89- }
42+ static final Iterable <Class <?>> HARDCODED_CLASSES = new HardcodedClasses ();
43+
44+ private static final List <NameResolverProvider > providers = ServiceProviders .loadAll (
45+ NameResolverProvider .class ,
46+ HARDCODED_CLASSES ,
47+ NameResolverProvider .class .getClassLoader (),
48+ new ServiceProviders .PriorityAccessor <NameResolverProvider >() {
49+ @ Override
50+ public boolean isAvailable (NameResolverProvider provider ) {
51+ return provider .isAvailable ();
52+ }
9053
91- /**
92- * Load providers from a hard-coded list. This avoids using getResource(), which has performance
93- * problems on Android (see https://github.com/grpc/grpc-java/issues/2037). Any provider that may
94- * be used on Android is free to be added here.
95- */
96- @ VisibleForTesting
97- public static Iterable <NameResolverProvider > getCandidatesViaHardCoded () {
98- // Class.forName(String) is used to remove the need for ProGuard configuration. Note that
99- // ProGuard does not detect usages of Class.forName(String, boolean, ClassLoader):
100- // https://sourceforge.net/p/proguard/bugs/418/
101- List <NameResolverProvider > list = new ArrayList <NameResolverProvider >();
102- try {
103- list .add (create (Class .forName ("io.grpc.internal.DnsNameResolverProvider" )));
104- } catch (ClassNotFoundException ex ) {
105- // ignore
106- }
107- return list ;
108- }
54+ @ Override
55+ public int getPriority (NameResolverProvider provider ) {
56+ return provider .priority ();
57+ }
58+ });
10959
110- @ VisibleForTesting
111- static NameResolverProvider create (Class <?> rawClass ) {
112- try {
113- return rawClass .asSubclass (NameResolverProvider .class ).getConstructor ().newInstance ();
114- } catch (Throwable t ) {
115- throw new ServiceConfigurationError (
116- "Provider " + rawClass .getName () + " could not be instantiated: " + t , t );
117- }
118- }
60+ private static final NameResolver .Factory factory = new NameResolverFactory (providers );
11961
12062 /**
12163 * Returns non-{@code null} ClassLoader-wide providers, in preference order.
@@ -133,18 +75,6 @@ static NameResolver.Factory asFactory(List<NameResolverProvider> providers) {
13375 return new NameResolverFactory (providers );
13476 }
13577
136- private static boolean isAndroid () {
137- try {
138- // Specify a class loader instead of null because we may be running under Robolectric
139- Class .forName ("android.app.Application" , /*initialize=*/ false ,
140- NameResolverProvider .class .getClassLoader ());
141- return true ;
142- } catch (Exception e ) {
143- // If Application isn't loaded, it might as well not be Android.
144- return false ;
145- }
146- }
147-
14878 /**
14979 * Whether this provider is available for use, taking the current environment into consideration.
15080 * If {@code false}, no other methods are safe to be called.
@@ -190,4 +120,21 @@ private void checkForProviders() {
190120 + "This is probably due to a broken build. If using ProGuard, check your configuration" );
191121 }
192122 }
123+
124+ @ VisibleForTesting
125+ static final class HardcodedClasses implements Iterable <Class <?>> {
126+ @ Override
127+ public Iterator <Class <?>> iterator () {
128+ List <Class <?>> list = new ArrayList <Class <?>>();
129+ // Class.forName(String) is used to remove the need for ProGuard configuration. Note that
130+ // ProGuard does not detect usages of Class.forName(String, boolean, ClassLoader):
131+ // https://sourceforge.net/p/proguard/bugs/418/
132+ try {
133+ list .add (Class .forName ("io.grpc.internal.DnsNameResolverProvider" ));
134+ } catch (ClassNotFoundException e ) {
135+ // ignore
136+ }
137+ return list .iterator ();
138+ }
139+ }
193140}
0 commit comments