Skip to content

Commit 538db03

Browse files
authored
api: add support for SocketAddress types in ManagedChannelProvider (grpc#9076)
* api: add support for SocketAddress types in ManagedChannelProvider also add support for SocketAddress types in NameResolverProvider Use scheme in target URI to select a NameRseolverProvider and get that provider's supported SocketAddress types. implement selection in ManagedChannelRegistry of appropriate ManagedChannelProvider based on NameResolver's SocketAddress types
1 parent 8e65700 commit 538db03

File tree

11 files changed

+381
-0
lines changed

11 files changed

+381
-0
lines changed

api/src/main/java/io/grpc/ManagedChannelProvider.java

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package io.grpc;
1818

1919
import com.google.common.base.Preconditions;
20+
import java.net.SocketAddress;
21+
import java.util.Collection;
2022

2123
/**
2224
* Provider of managed channels for transport agnostic consumption.
@@ -79,6 +81,11 @@ protected NewChannelBuilderResult newChannelBuilder(String target, ChannelCreden
7981
return NewChannelBuilderResult.error("ChannelCredentials are unsupported");
8082
}
8183

84+
/**
85+
* Returns the {@link SocketAddress} types this ManagedChannelProvider supports.
86+
*/
87+
protected abstract Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes();
88+
8289
public static final class NewChannelBuilderResult {
8390
private final ManagedChannelBuilder<?> channelBuilder;
8491
private final String error;

api/src/main/java/io/grpc/ManagedChannelRegistry.java

+36
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818

1919
import com.google.common.annotations.VisibleForTesting;
2020
import com.google.common.base.Preconditions;
21+
import java.net.SocketAddress;
22+
import java.net.URI;
23+
import java.net.URISyntaxException;
2124
import java.util.ArrayList;
25+
import java.util.Arrays;
26+
import java.util.Collection;
2227
import java.util.Collections;
2328
import java.util.Comparator;
2429
import java.util.LinkedHashSet;
@@ -144,6 +149,28 @@ static List<Class<?>> getHardCodedClasses() {
144149
}
145150

146151
ManagedChannelBuilder<?> newChannelBuilder(String target, ChannelCredentials creds) {
152+
return newChannelBuilder(NameResolverRegistry.getDefaultRegistry(), target, creds);
153+
}
154+
155+
@VisibleForTesting
156+
ManagedChannelBuilder<?> newChannelBuilder(NameResolverRegistry nameResolverRegistry,
157+
String target, ChannelCredentials creds) {
158+
NameResolverProvider nameResolverProvider = null;
159+
try {
160+
URI uri = new URI(target);
161+
nameResolverProvider = nameResolverRegistry.providers().get(uri.getScheme());
162+
} catch (URISyntaxException ignore) {
163+
// bad URI found, just ignore and continue
164+
}
165+
if (nameResolverProvider == null) {
166+
nameResolverProvider = nameResolverRegistry.providers().get(
167+
nameResolverRegistry.asFactory().getDefaultScheme());
168+
}
169+
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes
170+
= (nameResolverProvider != null)
171+
? nameResolverProvider.getProducedSocketAddressTypes() :
172+
Collections.emptySet();
173+
147174
List<ManagedChannelProvider> providers = providers();
148175
if (providers.isEmpty()) {
149176
throw new ProviderNotFoundException("No functional channel service provider found. "
@@ -152,6 +179,15 @@ ManagedChannelBuilder<?> newChannelBuilder(String target, ChannelCredentials cre
152179
}
153180
StringBuilder error = new StringBuilder();
154181
for (ManagedChannelProvider provider : providers()) {
182+
Collection<Class<? extends SocketAddress>> channelProviderSocketAddressTypes
183+
= provider.getSupportedSocketAddressTypes();
184+
if (!channelProviderSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
185+
error.append("; ");
186+
error.append(provider.getClass().getName());
187+
error.append(": does not support 1 or more of ");
188+
error.append(Arrays.toString(nameResolverSocketAddressTypes.toArray()));
189+
continue;
190+
}
155191
ManagedChannelProvider.NewChannelBuilderResult result
156192
= provider.newChannelBuilder(target, creds);
157193
if (result.getChannelBuilder() != null) {

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

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
package io.grpc;
1818

1919
import io.grpc.NameResolver.Factory;
20+
import java.net.InetSocketAddress;
21+
import java.net.SocketAddress;
22+
import java.util.Collection;
23+
import java.util.Collections;
2024

2125
/**
2226
* Provider of name resolvers for name agnostic consumption.
@@ -62,4 +66,14 @@ public abstract class NameResolverProvider extends NameResolver.Factory {
6266
protected String getScheme() {
6367
return getDefaultScheme();
6468
}
69+
70+
/**
71+
* Returns the {@link SocketAddress} types this provider's name-resolver is capable of producing.
72+
* This enables selection of the appropriate {@link ManagedChannelProvider} for a channel.
73+
*
74+
* @return the {@link SocketAddress} types this provider's name-resolver is capable of producing.
75+
*/
76+
protected Collection<Class<? extends SocketAddress>> getProducedSocketAddressTypes() {
77+
return Collections.singleton(InetSocketAddress.class);
78+
}
6579
}

api/src/test/java/io/grpc/ManagedChannelRegistryTest.java

+261
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
import static com.google.common.truth.Truth.assertThat;
2020
import static org.junit.Assert.fail;
2121

22+
import com.google.common.collect.ImmutableSet;
23+
import java.net.InetSocketAddress;
24+
import java.net.SocketAddress;
25+
import java.net.URI;
26+
import java.util.Collection;
27+
import java.util.Collections;
2228
import org.junit.Test;
2329
import org.junit.runner.RunWith;
2430
import org.junit.runners.JUnit4;
@@ -156,6 +162,256 @@ public void newChannelBuilder_noProvider() {
156162
}
157163
}
158164

165+
@Test
166+
public void newChannelBuilder_usesScheme() {
167+
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
168+
class SocketAddress1 extends SocketAddress {
169+
}
170+
171+
class SocketAddress2 extends SocketAddress {
172+
}
173+
174+
nameResolverRegistry.register(new BaseNameResolverProvider(true, 5, "sc1") {
175+
@Override
176+
protected Collection<Class<? extends SocketAddress>> getProducedSocketAddressTypes() {
177+
return Collections.singleton(SocketAddress1.class);
178+
}
179+
});
180+
nameResolverRegistry.register(new BaseNameResolverProvider(true, 6, "sc2") {
181+
@Override
182+
protected Collection<Class<? extends SocketAddress>> getProducedSocketAddressTypes() {
183+
fail("Should not be called");
184+
throw new AssertionError();
185+
}
186+
});
187+
188+
ManagedChannelRegistry registry = new ManagedChannelRegistry();
189+
registry.register(new BaseProvider(true, 5) {
190+
@Override
191+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
192+
return Collections.singleton(SocketAddress2.class);
193+
}
194+
195+
@Override
196+
public NewChannelBuilderResult newChannelBuilder(
197+
String passedTarget, ChannelCredentials passedCreds) {
198+
fail("Should not be called");
199+
throw new AssertionError();
200+
}
201+
});
202+
class MockChannelBuilder extends ForwardingChannelBuilder<MockChannelBuilder> {
203+
@Override public ManagedChannelBuilder<?> delegate() {
204+
throw new UnsupportedOperationException();
205+
}
206+
}
207+
208+
final ManagedChannelBuilder<?> mcb = new MockChannelBuilder();
209+
registry.register(new BaseProvider(true, 4) {
210+
@Override
211+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
212+
return Collections.singleton(SocketAddress1.class);
213+
}
214+
215+
@Override
216+
public NewChannelBuilderResult newChannelBuilder(
217+
String passedTarget, ChannelCredentials passedCreds) {
218+
return NewChannelBuilderResult.channelBuilder(mcb);
219+
}
220+
});
221+
assertThat(
222+
registry.newChannelBuilder(nameResolverRegistry, "sc1:" + target, creds)).isSameInstanceAs(
223+
mcb);
224+
}
225+
226+
@Test
227+
public void newChannelBuilder_unsupportedSocketAddressTypes() {
228+
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
229+
class SocketAddress1 extends SocketAddress {
230+
}
231+
232+
class SocketAddress2 extends SocketAddress {
233+
}
234+
235+
nameResolverRegistry.register(new BaseNameResolverProvider(true, 5, "sc1") {
236+
@Override
237+
protected Collection<Class<? extends SocketAddress>> getProducedSocketAddressTypes() {
238+
return ImmutableSet.of(SocketAddress1.class, SocketAddress2.class);
239+
}
240+
});
241+
242+
ManagedChannelRegistry registry = new ManagedChannelRegistry();
243+
registry.register(new BaseProvider(true, 5) {
244+
@Override
245+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
246+
return Collections.singleton(SocketAddress2.class);
247+
}
248+
249+
@Override
250+
public NewChannelBuilderResult newChannelBuilder(
251+
String passedTarget, ChannelCredentials passedCreds) {
252+
fail("Should not be called");
253+
throw new AssertionError();
254+
}
255+
});
256+
class MockChannelBuilder extends ForwardingChannelBuilder<MockChannelBuilder> {
257+
@Override public ManagedChannelBuilder<?> delegate() {
258+
throw new UnsupportedOperationException();
259+
}
260+
}
261+
262+
registry.register(new BaseProvider(true, 4) {
263+
@Override
264+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
265+
return Collections.singleton(SocketAddress1.class);
266+
}
267+
268+
@Override
269+
public NewChannelBuilderResult newChannelBuilder(
270+
String passedTarget, ChannelCredentials passedCreds) {
271+
fail("Should not be called");
272+
throw new AssertionError();
273+
}
274+
});
275+
try {
276+
registry.newChannelBuilder(nameResolverRegistry, "sc1:" + target, creds);
277+
fail("expected exception");
278+
} catch (ManagedChannelRegistry.ProviderNotFoundException ex) {
279+
assertThat(ex).hasMessageThat().contains("does not support 1 or more of");
280+
assertThat(ex).hasMessageThat().contains("SocketAddress1");
281+
assertThat(ex).hasMessageThat().contains("SocketAddress2");
282+
}
283+
}
284+
285+
@Test
286+
public void newChannelBuilder_emptySet_asDefault() {
287+
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
288+
289+
ManagedChannelRegistry registry = new ManagedChannelRegistry();
290+
class MockChannelBuilder extends ForwardingChannelBuilder<MockChannelBuilder> {
291+
@Override public ManagedChannelBuilder<?> delegate() {
292+
throw new UnsupportedOperationException();
293+
}
294+
}
295+
296+
final ManagedChannelBuilder<?> mcb = new MockChannelBuilder();
297+
registry.register(new BaseProvider(true, 4) {
298+
@Override
299+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
300+
return Collections.emptySet();
301+
}
302+
303+
@Override
304+
public NewChannelBuilderResult newChannelBuilder(
305+
String passedTarget, ChannelCredentials passedCreds) {
306+
return NewChannelBuilderResult.channelBuilder(mcb);
307+
}
308+
});
309+
assertThat(
310+
registry.newChannelBuilder(nameResolverRegistry, "sc1:" + target, creds)).isSameInstanceAs(
311+
mcb);
312+
}
313+
314+
@Test
315+
public void newChannelBuilder_noSchemeUsesDefaultScheme() {
316+
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
317+
class SocketAddress1 extends SocketAddress {
318+
}
319+
320+
nameResolverRegistry.register(new BaseNameResolverProvider(true, 5, "sc1") {
321+
@Override
322+
protected Collection<Class<? extends SocketAddress>> getProducedSocketAddressTypes() {
323+
return Collections.singleton(SocketAddress1.class);
324+
}
325+
});
326+
327+
ManagedChannelRegistry registry = new ManagedChannelRegistry();
328+
class MockChannelBuilder extends ForwardingChannelBuilder<MockChannelBuilder> {
329+
@Override public ManagedChannelBuilder<?> delegate() {
330+
throw new UnsupportedOperationException();
331+
}
332+
}
333+
334+
final ManagedChannelBuilder<?> mcb = new MockChannelBuilder();
335+
registry.register(new BaseProvider(true, 4) {
336+
@Override
337+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
338+
return Collections.singleton(SocketAddress1.class);
339+
}
340+
341+
@Override
342+
public NewChannelBuilderResult newChannelBuilder(
343+
String passedTarget, ChannelCredentials passedCreds) {
344+
return NewChannelBuilderResult.channelBuilder(mcb);
345+
}
346+
});
347+
assertThat(registry.newChannelBuilder(nameResolverRegistry, target, creds)).isSameInstanceAs(
348+
mcb);
349+
}
350+
351+
@Test
352+
public void newChannelBuilder_badUri() {
353+
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
354+
class SocketAddress1 extends SocketAddress {
355+
}
356+
357+
ManagedChannelRegistry registry = new ManagedChannelRegistry();
358+
359+
class MockChannelBuilder extends ForwardingChannelBuilder<MockChannelBuilder> {
360+
@Override public ManagedChannelBuilder<?> delegate() {
361+
throw new UnsupportedOperationException();
362+
}
363+
}
364+
365+
final ManagedChannelBuilder<?> mcb = new MockChannelBuilder();
366+
registry.register(new BaseProvider(true, 4) {
367+
@Override
368+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
369+
return Collections.singleton(SocketAddress1.class);
370+
}
371+
372+
@Override
373+
public NewChannelBuilderResult newChannelBuilder(
374+
String passedTarget, ChannelCredentials passedCreds) {
375+
return NewChannelBuilderResult.channelBuilder(mcb);
376+
}
377+
});
378+
assertThat(
379+
registry.newChannelBuilder(nameResolverRegistry, ":testing123", creds)).isSameInstanceAs(
380+
mcb);
381+
}
382+
383+
private static class BaseNameResolverProvider extends NameResolverProvider {
384+
private final boolean isAvailable;
385+
private final int priority;
386+
private final String defaultScheme;
387+
388+
public BaseNameResolverProvider(boolean isAvailable, int priority, String defaultScheme) {
389+
this.isAvailable = isAvailable;
390+
this.priority = priority;
391+
this.defaultScheme = defaultScheme;
392+
}
393+
394+
@Override
395+
public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
396+
return null;
397+
}
398+
399+
@Override
400+
public String getDefaultScheme() {
401+
return defaultScheme;
402+
}
403+
404+
@Override
405+
protected boolean isAvailable() {
406+
return isAvailable;
407+
}
408+
409+
@Override
410+
protected int priority() {
411+
return priority;
412+
}
413+
}
414+
159415
private static class BaseProvider extends ManagedChannelProvider {
160416
private final boolean isAvailable;
161417
private final int priority;
@@ -184,5 +440,10 @@ protected ManagedChannelBuilder<?> builderForAddress(String name, int port) {
184440
protected ManagedChannelBuilder<?> builderForTarget(String target) {
185441
throw new UnsupportedOperationException();
186442
}
443+
444+
@Override
445+
protected Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
446+
return Collections.singleton(InetSocketAddress.class);
447+
}
187448
}
188449
}

0 commit comments

Comments
 (0)