Skip to content

Commit a423900

Browse files
authored
api, core, services: make ProtoReflectionService interceptor compatible (grpc#6967)
Eliminate the hack of InternalNotifyOnBuild mechanism for letting ProtoReflectionService get access to the Sever instance, which makes ProtoReflectionService incompatible with server interceptors. This change put the Server instance into the Context and let the ProtoReflectionService RPC obtain it in its RPC Context. Also enhanced ProtoReflectionService so that one service instance can be used across multiple servers.
1 parent 4674b27 commit a423900

File tree

9 files changed

+384
-59
lines changed

9 files changed

+384
-59
lines changed

api/src/main/java/io/grpc/InternalNotifyOnServerBuild.java renamed to api/src/main/java/io/grpc/InternalServer.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 The gRPC Authors
2+
* Copyright 2020 The gRPC Authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,12 +17,15 @@
1717
package io.grpc;
1818

1919
/**
20-
* Provides a callback method for a service to receive a reference to its server. The contract with
21-
* {@link ServerBuilder} is that this method will be called on all registered services implementing
22-
* the interface after build() has been called and before the {@link Server} instance is returned.
20+
* Internal accessor for getting the {@link Server} instance inside server RPC {@link Context}.
21+
* This is intended for usage internal to the gRPC team. If you think you need to use
22+
* this, contact the gRPC team first.
2323
*/
2424
@Internal
25-
public interface InternalNotifyOnServerBuild {
26-
/** Notifies the service that the server has been built. */
27-
void notifyOnBuild(Server server);
25+
public class InternalServer {
26+
public static final Context.Key<Server> SERVER_CONTEXT_KEY = Server.SERVER_CONTEXT_KEY;
27+
28+
// Prevent instantiation.
29+
private InternalServer() {
30+
}
2831
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
@ThreadSafe
3131
public abstract class Server {
3232

33+
/**
34+
* Key for accessing the {@link Server} instance inside server RPC {@link Context}. It's
35+
* unclear to us what users would need. If you think you need to use this, please file an
36+
* issue for us to discuss a public API.
37+
*/
38+
static final Context.Key<Server> SERVER_CONTEXT_KEY =
39+
Context.key("io.grpc.Server");
40+
3341
/**
3442
* Bind and start the server. After this call returns, clients may begin connecting to the
3543
* listening socket(s).

core/src/main/java/io/grpc/internal/AbstractServerImplBuilder.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import io.grpc.DecompressorRegistry;
3030
import io.grpc.HandlerRegistry;
3131
import io.grpc.InternalChannelz;
32-
import io.grpc.InternalNotifyOnServerBuild;
3332
import io.grpc.Server;
3433
import io.grpc.ServerBuilder;
3534
import io.grpc.ServerInterceptor;
@@ -77,7 +76,6 @@ public static ServerBuilder<?> forPort(int port) {
7776
new InternalHandlerRegistry.Builder();
7877
final List<ServerTransportFilter> transportFilters = new ArrayList<>();
7978
final List<ServerInterceptor> interceptors = new ArrayList<>();
80-
private final List<InternalNotifyOnServerBuild> notifyOnBuildList = new ArrayList<>();
8179
private final List<ServerStreamTracer.Factory> streamTracerFactories = new ArrayList<>();
8280
HandlerRegistry fallbackRegistry = DEFAULT_FALLBACK_REGISTRY;
8381
ObjectPool<? extends Executor> executorPool = DEFAULT_EXECUTOR_POOL;
@@ -114,9 +112,6 @@ public final T addService(ServerServiceDefinition service) {
114112

115113
@Override
116114
public final T addService(BindableService bindableService) {
117-
if (bindableService instanceof InternalNotifyOnServerBuild) {
118-
notifyOnBuildList.add((InternalNotifyOnServerBuild) bindableService);
119-
}
120115
return addService(checkNotNull(bindableService, "bindableService").bindService());
121116
}
122117

@@ -222,14 +217,7 @@ protected void setDeadlineTicker(Deadline.Ticker ticker) {
222217

223218
@Override
224219
public final Server build() {
225-
ServerImpl server = new ServerImpl(
226-
this,
227-
buildTransportServers(getTracerFactories()),
228-
Context.ROOT);
229-
for (InternalNotifyOnServerBuild notifyTarget : notifyOnBuildList) {
230-
notifyTarget.notifyOnBuild(server);
231-
}
232-
return server;
220+
return new ServerImpl(this, buildTransportServers(getTracerFactories()), Context.ROOT);
233221
}
234222

235223
@VisibleForTesting

core/src/main/java/io/grpc/internal/ServerImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,10 @@ private Context.CancellableContext createContext(
593593
Metadata headers, StatsTraceContext statsTraceCtx) {
594594
Long timeoutNanos = headers.get(TIMEOUT_KEY);
595595

596-
Context baseContext = statsTraceCtx.serverFilterContext(rootContext);
596+
Context baseContext =
597+
statsTraceCtx
598+
.serverFilterContext(rootContext)
599+
.withValue(io.grpc.InternalServer.SERVER_CONTEXT_KEY, ServerImpl.this);
597600

598601
if (timeoutNanos == null) {
599602
return baseContext.withCancellation();

core/src/test/java/io/grpc/internal/ServerImplTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ public ServerCall.Listener<String> startCall(
561561
Context callContext = callContextReference.get();
562562
assertNotNull(callContext);
563563
assertEquals("context added by tracer", SERVER_TRACER_ADDED_KEY.get(callContext));
564+
assertEquals(server, io.grpc.InternalServer.SERVER_CONTEXT_KEY.get(callContext));
564565

565566
streamListener.messagesAvailable(new SingleMessageProducer(STRING_MARSHALLER.stream(request)));
566567
assertEquals(1, executor.runDueTasks());
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
package io.grpc.reflection.testing;
2+
3+
import static io.grpc.MethodDescriptor.generateFullMethodName;
4+
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
5+
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
6+
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
7+
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
8+
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
9+
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
10+
import static io.grpc.stub.ClientCalls.futureUnaryCall;
11+
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
12+
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
13+
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
14+
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
15+
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
16+
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
17+
18+
/**
19+
*/
20+
@javax.annotation.Generated(
21+
value = "by gRPC proto compiler",
22+
comments = "Source: io/grpc/reflection/testing/reflection_test.proto")
23+
public final class AnotherReflectableServiceGrpc {
24+
25+
private AnotherReflectableServiceGrpc() {}
26+
27+
public static final String SERVICE_NAME = "grpc.reflection.testing.AnotherReflectableService";
28+
29+
// Static method descriptors that strictly reflect the proto.
30+
private static volatile io.grpc.MethodDescriptor<io.grpc.reflection.testing.Request,
31+
io.grpc.reflection.testing.Reply> getMethodMethod;
32+
33+
@io.grpc.stub.annotations.RpcMethod(
34+
fullMethodName = SERVICE_NAME + '/' + "Method",
35+
requestType = io.grpc.reflection.testing.Request.class,
36+
responseType = io.grpc.reflection.testing.Reply.class,
37+
methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
38+
public static io.grpc.MethodDescriptor<io.grpc.reflection.testing.Request,
39+
io.grpc.reflection.testing.Reply> getMethodMethod() {
40+
io.grpc.MethodDescriptor<io.grpc.reflection.testing.Request, io.grpc.reflection.testing.Reply> getMethodMethod;
41+
if ((getMethodMethod = AnotherReflectableServiceGrpc.getMethodMethod) == null) {
42+
synchronized (AnotherReflectableServiceGrpc.class) {
43+
if ((getMethodMethod = AnotherReflectableServiceGrpc.getMethodMethod) == null) {
44+
AnotherReflectableServiceGrpc.getMethodMethod = getMethodMethod =
45+
io.grpc.MethodDescriptor.<io.grpc.reflection.testing.Request, io.grpc.reflection.testing.Reply>newBuilder()
46+
.setType(io.grpc.MethodDescriptor.MethodType.UNARY)
47+
.setFullMethodName(generateFullMethodName(SERVICE_NAME, "Method"))
48+
.setSampledToLocalTracing(true)
49+
.setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
50+
io.grpc.reflection.testing.Request.getDefaultInstance()))
51+
.setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
52+
io.grpc.reflection.testing.Reply.getDefaultInstance()))
53+
.setSchemaDescriptor(new AnotherReflectableServiceMethodDescriptorSupplier("Method"))
54+
.build();
55+
}
56+
}
57+
}
58+
return getMethodMethod;
59+
}
60+
61+
/**
62+
* Creates a new async stub that supports all call types for the service
63+
*/
64+
public static AnotherReflectableServiceStub newStub(io.grpc.Channel channel) {
65+
io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceStub> factory =
66+
new io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceStub>() {
67+
@java.lang.Override
68+
public AnotherReflectableServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
69+
return new AnotherReflectableServiceStub(channel, callOptions);
70+
}
71+
};
72+
return AnotherReflectableServiceStub.newStub(factory, channel);
73+
}
74+
75+
/**
76+
* Creates a new blocking-style stub that supports unary and streaming output calls on the service
77+
*/
78+
public static AnotherReflectableServiceBlockingStub newBlockingStub(
79+
io.grpc.Channel channel) {
80+
io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceBlockingStub> factory =
81+
new io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceBlockingStub>() {
82+
@java.lang.Override
83+
public AnotherReflectableServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
84+
return new AnotherReflectableServiceBlockingStub(channel, callOptions);
85+
}
86+
};
87+
return AnotherReflectableServiceBlockingStub.newStub(factory, channel);
88+
}
89+
90+
/**
91+
* Creates a new ListenableFuture-style stub that supports unary calls on the service
92+
*/
93+
public static AnotherReflectableServiceFutureStub newFutureStub(
94+
io.grpc.Channel channel) {
95+
io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceFutureStub> factory =
96+
new io.grpc.stub.AbstractStub.StubFactory<AnotherReflectableServiceFutureStub>() {
97+
@java.lang.Override
98+
public AnotherReflectableServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
99+
return new AnotherReflectableServiceFutureStub(channel, callOptions);
100+
}
101+
};
102+
return AnotherReflectableServiceFutureStub.newStub(factory, channel);
103+
}
104+
105+
/**
106+
*/
107+
public static abstract class AnotherReflectableServiceImplBase implements io.grpc.BindableService {
108+
109+
/**
110+
*/
111+
public void method(io.grpc.reflection.testing.Request request,
112+
io.grpc.stub.StreamObserver<io.grpc.reflection.testing.Reply> responseObserver) {
113+
asyncUnimplementedUnaryCall(getMethodMethod(), responseObserver);
114+
}
115+
116+
@java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
117+
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
118+
.addMethod(
119+
getMethodMethod(),
120+
asyncUnaryCall(
121+
new MethodHandlers<
122+
io.grpc.reflection.testing.Request,
123+
io.grpc.reflection.testing.Reply>(
124+
this, METHODID_METHOD)))
125+
.build();
126+
}
127+
}
128+
129+
/**
130+
*/
131+
public static final class AnotherReflectableServiceStub extends io.grpc.stub.AbstractAsyncStub<AnotherReflectableServiceStub> {
132+
private AnotherReflectableServiceStub(
133+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
134+
super(channel, callOptions);
135+
}
136+
137+
@java.lang.Override
138+
protected AnotherReflectableServiceStub build(
139+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
140+
return new AnotherReflectableServiceStub(channel, callOptions);
141+
}
142+
143+
/**
144+
*/
145+
public void method(io.grpc.reflection.testing.Request request,
146+
io.grpc.stub.StreamObserver<io.grpc.reflection.testing.Reply> responseObserver) {
147+
asyncUnaryCall(
148+
getChannel().newCall(getMethodMethod(), getCallOptions()), request, responseObserver);
149+
}
150+
}
151+
152+
/**
153+
*/
154+
public static final class AnotherReflectableServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub<AnotherReflectableServiceBlockingStub> {
155+
private AnotherReflectableServiceBlockingStub(
156+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
157+
super(channel, callOptions);
158+
}
159+
160+
@java.lang.Override
161+
protected AnotherReflectableServiceBlockingStub build(
162+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
163+
return new AnotherReflectableServiceBlockingStub(channel, callOptions);
164+
}
165+
166+
/**
167+
*/
168+
public io.grpc.reflection.testing.Reply method(io.grpc.reflection.testing.Request request) {
169+
return blockingUnaryCall(
170+
getChannel(), getMethodMethod(), getCallOptions(), request);
171+
}
172+
}
173+
174+
/**
175+
*/
176+
public static final class AnotherReflectableServiceFutureStub extends io.grpc.stub.AbstractFutureStub<AnotherReflectableServiceFutureStub> {
177+
private AnotherReflectableServiceFutureStub(
178+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
179+
super(channel, callOptions);
180+
}
181+
182+
@java.lang.Override
183+
protected AnotherReflectableServiceFutureStub build(
184+
io.grpc.Channel channel, io.grpc.CallOptions callOptions) {
185+
return new AnotherReflectableServiceFutureStub(channel, callOptions);
186+
}
187+
188+
/**
189+
*/
190+
public com.google.common.util.concurrent.ListenableFuture<io.grpc.reflection.testing.Reply> method(
191+
io.grpc.reflection.testing.Request request) {
192+
return futureUnaryCall(
193+
getChannel().newCall(getMethodMethod(), getCallOptions()), request);
194+
}
195+
}
196+
197+
private static final int METHODID_METHOD = 0;
198+
199+
private static final class MethodHandlers<Req, Resp> implements
200+
io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
201+
io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
202+
io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
203+
io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
204+
private final AnotherReflectableServiceImplBase serviceImpl;
205+
private final int methodId;
206+
207+
MethodHandlers(AnotherReflectableServiceImplBase serviceImpl, int methodId) {
208+
this.serviceImpl = serviceImpl;
209+
this.methodId = methodId;
210+
}
211+
212+
@java.lang.Override
213+
@java.lang.SuppressWarnings("unchecked")
214+
public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
215+
switch (methodId) {
216+
case METHODID_METHOD:
217+
serviceImpl.method((io.grpc.reflection.testing.Request) request,
218+
(io.grpc.stub.StreamObserver<io.grpc.reflection.testing.Reply>) responseObserver);
219+
break;
220+
default:
221+
throw new AssertionError();
222+
}
223+
}
224+
225+
@java.lang.Override
226+
@java.lang.SuppressWarnings("unchecked")
227+
public io.grpc.stub.StreamObserver<Req> invoke(
228+
io.grpc.stub.StreamObserver<Resp> responseObserver) {
229+
switch (methodId) {
230+
default:
231+
throw new AssertionError();
232+
}
233+
}
234+
}
235+
236+
private static abstract class AnotherReflectableServiceBaseDescriptorSupplier
237+
implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier {
238+
AnotherReflectableServiceBaseDescriptorSupplier() {}
239+
240+
@java.lang.Override
241+
public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {
242+
return io.grpc.reflection.testing.ReflectionTestProto.getDescriptor();
243+
}
244+
245+
@java.lang.Override
246+
public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {
247+
return getFileDescriptor().findServiceByName("AnotherReflectableService");
248+
}
249+
}
250+
251+
private static final class AnotherReflectableServiceFileDescriptorSupplier
252+
extends AnotherReflectableServiceBaseDescriptorSupplier {
253+
AnotherReflectableServiceFileDescriptorSupplier() {}
254+
}
255+
256+
private static final class AnotherReflectableServiceMethodDescriptorSupplier
257+
extends AnotherReflectableServiceBaseDescriptorSupplier
258+
implements io.grpc.protobuf.ProtoMethodDescriptorSupplier {
259+
private final String methodName;
260+
261+
AnotherReflectableServiceMethodDescriptorSupplier(String methodName) {
262+
this.methodName = methodName;
263+
}
264+
265+
@java.lang.Override
266+
public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {
267+
return getServiceDescriptor().findMethodByName(methodName);
268+
}
269+
}
270+
271+
private static volatile io.grpc.ServiceDescriptor serviceDescriptor;
272+
273+
public static io.grpc.ServiceDescriptor getServiceDescriptor() {
274+
io.grpc.ServiceDescriptor result = serviceDescriptor;
275+
if (result == null) {
276+
synchronized (AnotherReflectableServiceGrpc.class) {
277+
result = serviceDescriptor;
278+
if (result == null) {
279+
serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME)
280+
.setSchemaDescriptor(new AnotherReflectableServiceFileDescriptorSupplier())
281+
.addMethod(getMethodMethod())
282+
.build();
283+
}
284+
}
285+
}
286+
return result;
287+
}
288+
}

0 commit comments

Comments
 (0)