Skip to content

Commit 2a93e6b

Browse files
authored
core: NameResolverProvider should use ServiceProviders util (grpc#4005)
1 parent 2996207 commit 2a93e6b

5 files changed

Lines changed: 159 additions & 284 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2018, gRPC Authors All rights reserved.
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;
18+
19+
import com.google.common.annotations.VisibleForTesting;
20+
21+
public class InternalNameResolverProvider {
22+
@VisibleForTesting
23+
public static final Iterable<Class<?>> HARDCODED_CLASSES =
24+
NameResolverProvider.HARDCODED_CLASSES;
25+
}

core/src/main/java/io/grpc/NameResolverProvider.java

Lines changed: 35 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@
2020
import com.google.common.base.Preconditions;
2121
import java.net.URI;
2222
import java.util.ArrayList;
23-
import java.util.Collections;
24-
import java.util.Comparator;
23+
import java.util.Iterator;
2524
import 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

Comments
 (0)