mirror of https://github.com/grpc/grpc-java.git
Support BinderChannelBuilder.forTarget. (#8633)
Allows this class to be used with custom name resolvers.
This commit is contained in:
parent
59c6b49fd4
commit
14eb3b265f
|
|
@ -36,11 +36,13 @@ import io.grpc.CallOptions;
|
||||||
import io.grpc.ManagedChannel;
|
import io.grpc.ManagedChannel;
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.grpc.MethodDescriptor;
|
import io.grpc.MethodDescriptor;
|
||||||
|
import io.grpc.NameResolverRegistry;
|
||||||
import io.grpc.Server;
|
import io.grpc.Server;
|
||||||
import io.grpc.ServerCallHandler;
|
import io.grpc.ServerCallHandler;
|
||||||
import io.grpc.ServerInterceptors;
|
import io.grpc.ServerInterceptors;
|
||||||
import io.grpc.ServerServiceDefinition;
|
import io.grpc.ServerServiceDefinition;
|
||||||
import io.grpc.internal.GrpcUtil;
|
import io.grpc.internal.GrpcUtil;
|
||||||
|
import io.grpc.internal.testing.FakeNameResolverProvider;
|
||||||
import io.grpc.stub.ClientCalls;
|
import io.grpc.stub.ClientCalls;
|
||||||
import io.grpc.stub.ServerCalls;
|
import io.grpc.stub.ServerCalls;
|
||||||
import io.grpc.stub.StreamObserver;
|
import io.grpc.stub.StreamObserver;
|
||||||
|
|
@ -66,6 +68,7 @@ public final class BinderChannelSmokeTest {
|
||||||
|
|
||||||
private static final int SLIGHTLY_MORE_THAN_ONE_BLOCK = 16 * 1024 + 100;
|
private static final int SLIGHTLY_MORE_THAN_ONE_BLOCK = 16 * 1024 + 100;
|
||||||
private static final String MSG = "Some text which will be repeated many many times";
|
private static final String MSG = "Some text which will be repeated many many times";
|
||||||
|
private static final String SERVER_TARGET_URI = "fake://server";
|
||||||
|
|
||||||
final MethodDescriptor<String, String> method =
|
final MethodDescriptor<String, String> method =
|
||||||
MethodDescriptor.newBuilder(StringMarshaller.INSTANCE, StringMarshaller.INSTANCE)
|
MethodDescriptor.newBuilder(StringMarshaller.INSTANCE, StringMarshaller.INSTANCE)
|
||||||
|
|
@ -85,7 +88,7 @@ public final class BinderChannelSmokeTest {
|
||||||
.setType(MethodDescriptor.MethodType.BIDI_STREAMING)
|
.setType(MethodDescriptor.MethodType.BIDI_STREAMING)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
AndroidComponentAddress serverAddress;
|
FakeNameResolverProvider fakeNameResolverProvider;
|
||||||
ManagedChannel channel;
|
ManagedChannel channel;
|
||||||
AtomicReference<Metadata> headersCapture = new AtomicReference<>();
|
AtomicReference<Metadata> headersCapture = new AtomicReference<>();
|
||||||
|
|
||||||
|
|
@ -118,6 +121,8 @@ public final class BinderChannelSmokeTest {
|
||||||
TestUtils.recordRequestHeadersInterceptor(headersCapture));
|
TestUtils.recordRequestHeadersInterceptor(headersCapture));
|
||||||
|
|
||||||
AndroidComponentAddress serverAddress = HostServices.allocateService(appContext);
|
AndroidComponentAddress serverAddress = HostServices.allocateService(appContext);
|
||||||
|
fakeNameResolverProvider = new FakeNameResolverProvider(SERVER_TARGET_URI, serverAddress);
|
||||||
|
NameResolverRegistry.getDefaultRegistry().register(fakeNameResolverProvider);
|
||||||
HostServices.configureService(serverAddress,
|
HostServices.configureService(serverAddress,
|
||||||
HostServices.serviceParamsBuilder()
|
HostServices.serviceParamsBuilder()
|
||||||
.setServerFactory((service, receiver) ->
|
.setServerFactory((service, receiver) ->
|
||||||
|
|
@ -132,6 +137,7 @@ public final class BinderChannelSmokeTest {
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
channel.shutdownNow();
|
channel.shutdownNow();
|
||||||
|
NameResolverRegistry.getDefaultRegistry().deregister(fakeNameResolverProvider);
|
||||||
HostServices.awaitServiceShutdown();
|
HostServices.awaitServiceShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,6 +198,12 @@ public final class BinderChannelSmokeTest {
|
||||||
assertThat(headersCapture.get().get(GrpcUtil.TIMEOUT_KEY)).isGreaterThan(0);
|
assertThat(headersCapture.get().get(GrpcUtil.TIMEOUT_KEY)).isGreaterThan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectViaTargetUri() throws Exception {
|
||||||
|
channel = BinderChannelBuilder.forTarget(SERVER_TARGET_URI, appContext).build();
|
||||||
|
assertThat(doCall("Hello").get()).isEqualTo("Hello");
|
||||||
|
}
|
||||||
|
|
||||||
private static String createLargeString(int size) {
|
private static String createLargeString(int size) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
while (sb.length() < size) {
|
while (sb.length() < size) {
|
||||||
|
|
|
||||||
|
|
@ -67,13 +67,35 @@ public final class BinderChannelBuilder
|
||||||
* <p>You the caller are responsible for managing the lifecycle of any channels built by the
|
* <p>You the caller are responsible for managing the lifecycle of any channels built by the
|
||||||
* resulting builder. They will not be shut down automatically.
|
* resulting builder. They will not be shut down automatically.
|
||||||
*
|
*
|
||||||
* @param targetAddress the {@link AndroidComponentAddress} referencing the service to bind to.
|
* @param directAddress the {@link AndroidComponentAddress} referencing the service to bind to.
|
||||||
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
|
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
|
||||||
* @return a new builder
|
* @return a new builder
|
||||||
*/
|
*/
|
||||||
public static BinderChannelBuilder forAddress(
|
public static BinderChannelBuilder forAddress(
|
||||||
AndroidComponentAddress targetAddress, Context sourceContext) {
|
AndroidComponentAddress directAddress, Context sourceContext) {
|
||||||
return new BinderChannelBuilder(targetAddress, sourceContext);
|
return new BinderChannelBuilder(
|
||||||
|
checkNotNull(directAddress, "directAddress"), null, sourceContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a channel builder that will bind to a remote Android service, via a string
|
||||||
|
* target name which will be resolved.
|
||||||
|
*
|
||||||
|
* <p>The underlying Android binding will be torn down when the channel becomes idle. This happens
|
||||||
|
* after 30 minutes without use by default but can be configured via {@link
|
||||||
|
* ManagedChannelBuilder#idleTimeout(long, TimeUnit)} or triggered manually with {@link
|
||||||
|
* ManagedChannel#enterIdle()}.
|
||||||
|
*
|
||||||
|
* <p>You the caller are responsible for managing the lifecycle of any channels built by the
|
||||||
|
* resulting builder. They will not be shut down automatically.
|
||||||
|
*
|
||||||
|
* @param target A target uri which should resolve into an {@link AndroidComponentAddress}
|
||||||
|
* referencing the service to bind to.
|
||||||
|
* @param sourceContext the context to bind from (e.g. The current Activity or Application).
|
||||||
|
* @return a new builder
|
||||||
|
*/
|
||||||
|
public static BinderChannelBuilder forTarget(String target, Context sourceContext) {
|
||||||
|
return new BinderChannelBuilder(null, checkNotNull(target, "target"), sourceContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -88,7 +110,7 @@ public final class BinderChannelBuilder
|
||||||
/**
|
/**
|
||||||
* Always fails. Call {@link #forAddress(AndroidComponentAddress, Context)} instead.
|
* Always fails. Call {@link #forAddress(AndroidComponentAddress, Context)} instead.
|
||||||
*/
|
*/
|
||||||
@DoNotCall("Unsupported. Use forAddress(AndroidComponentAddress, Context) instead")
|
@DoNotCall("Unsupported. Use forTarget(String, Context) instead")
|
||||||
public static BinderChannelBuilder forTarget(String target) {
|
public static BinderChannelBuilder forTarget(String target) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
"call forAddress(AndroidComponentAddress, Context) instead");
|
"call forAddress(AndroidComponentAddress, Context) instead");
|
||||||
|
|
@ -104,9 +126,11 @@ public final class BinderChannelBuilder
|
||||||
private BindServiceFlags bindServiceFlags;
|
private BindServiceFlags bindServiceFlags;
|
||||||
|
|
||||||
private BinderChannelBuilder(
|
private BinderChannelBuilder(
|
||||||
AndroidComponentAddress targetAddress,
|
@Nullable AndroidComponentAddress directAddress,
|
||||||
|
@Nullable String target,
|
||||||
Context sourceContext) {
|
Context sourceContext) {
|
||||||
mainThreadExecutor = ContextCompat.getMainExecutor(sourceContext);
|
mainThreadExecutor =
|
||||||
|
ContextCompat.getMainExecutor(checkNotNull(sourceContext, "sourceContext"));
|
||||||
securityPolicy = SecurityPolicies.internalOnly();
|
securityPolicy = SecurityPolicies.internalOnly();
|
||||||
inboundParcelablePolicy = InboundParcelablePolicy.DEFAULT;
|
inboundParcelablePolicy = InboundParcelablePolicy.DEFAULT;
|
||||||
bindServiceFlags = BindServiceFlags.DEFAULTS;
|
bindServiceFlags = BindServiceFlags.DEFAULTS;
|
||||||
|
|
@ -126,12 +150,20 @@ public final class BinderChannelBuilder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
managedChannelImplBuilder =
|
if (directAddress != null) {
|
||||||
new ManagedChannelImplBuilder(
|
managedChannelImplBuilder =
|
||||||
targetAddress,
|
new ManagedChannelImplBuilder(
|
||||||
targetAddress.getAuthority(),
|
directAddress,
|
||||||
new BinderChannelTransportFactoryBuilder(),
|
directAddress.getAuthority(),
|
||||||
null);
|
new BinderChannelTransportFactoryBuilder(),
|
||||||
|
null);
|
||||||
|
} else {
|
||||||
|
managedChannelImplBuilder =
|
||||||
|
new ManagedChannelImplBuilder(
|
||||||
|
target,
|
||||||
|
new BinderChannelTransportFactoryBuilder(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The gRPC Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.grpc.internal.testing;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import io.grpc.EquivalentAddressGroup;
|
||||||
|
import io.grpc.NameResolver;
|
||||||
|
import io.grpc.NameResolverProvider;
|
||||||
|
import io.grpc.Status;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/** A name resolver to always resolve the given URI into the given address. */
|
||||||
|
public final class FakeNameResolverProvider extends NameResolverProvider {
|
||||||
|
|
||||||
|
private final URI targetUri;
|
||||||
|
private final SocketAddress address;
|
||||||
|
|
||||||
|
public FakeNameResolverProvider(String targetUri, SocketAddress address) {
|
||||||
|
this.targetUri = URI.create(targetUri);
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
|
||||||
|
if (targetUri.equals(this.targetUri)) {
|
||||||
|
return new FakeNameResolver(address);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int priority() {
|
||||||
|
return 5; // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultScheme() {
|
||||||
|
return targetUri.getScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A single name resolver. */
|
||||||
|
private static final class FakeNameResolver extends NameResolver {
|
||||||
|
private static final String AUTHORITY = "fake-authority";
|
||||||
|
|
||||||
|
private final SocketAddress address;
|
||||||
|
private volatile boolean shutdown;
|
||||||
|
|
||||||
|
private FakeNameResolver(SocketAddress address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Listener2 listener) {
|
||||||
|
if (shutdown) {
|
||||||
|
listener.onError(Status.FAILED_PRECONDITION.withDescription("Resolver is shutdown"));
|
||||||
|
} else {
|
||||||
|
listener.onResult(
|
||||||
|
ResolutionResult.newBuilder()
|
||||||
|
.setAddresses(ImmutableList.of(new EquivalentAddressGroup(address)))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceAuthority() {
|
||||||
|
return AUTHORITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
shutdown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue