Skip to content

Commit 395fae5

Browse files
authored
api: Add GlobalInterceptors API (grpc#9235)
* added GlobalInterceptors API
1 parent 65bf2dc commit 395fae5

File tree

3 files changed

+332
-0
lines changed

3 files changed

+332
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2022 The gRPC Authors
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 java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.List;
22+
23+
/** The collection of global interceptors and global server stream tracers. */
24+
@Internal
25+
final class GlobalInterceptors {
26+
private static List<ClientInterceptor> clientInterceptors = Collections.emptyList();
27+
private static List<ServerInterceptor> serverInterceptors = Collections.emptyList();
28+
private static List<ServerStreamTracer.Factory> serverStreamTracerFactories =
29+
Collections.emptyList();
30+
private static boolean isGlobalInterceptorsTracersSet;
31+
private static boolean isGlobalInterceptorsTracersGet;
32+
33+
// Prevent instantiation
34+
private GlobalInterceptors() {}
35+
36+
/**
37+
* Sets the list of global interceptors and global server stream tracers.
38+
*
39+
* <p>If {@code setInterceptorsTracers()} is called again, this method will throw {@link
40+
* IllegalStateException}.
41+
*
42+
* <p>It is only safe to call early. This method throws {@link IllegalStateException} after any of
43+
* the get calls [{@link #getClientInterceptors()}, {@link #getServerInterceptors()} or {@link
44+
* #getServerStreamTracerFactories()}] has been called, in order to limit changes to the result of
45+
* {@code setInterceptorsTracers()}.
46+
*
47+
* @param clientInterceptorList list of {@link ClientInterceptor} that make up global Client
48+
* Interceptors.
49+
* @param serverInterceptorList list of {@link ServerInterceptor} that make up global Server
50+
* Interceptors.
51+
* @param serverStreamTracerFactoryList list of {@link ServerStreamTracer.Factory} that make up
52+
* global ServerStreamTracer factories.
53+
*/
54+
static synchronized void setInterceptorsTracers(
55+
List<ClientInterceptor> clientInterceptorList,
56+
List<ServerInterceptor> serverInterceptorList,
57+
List<ServerStreamTracer.Factory> serverStreamTracerFactoryList) {
58+
if (isGlobalInterceptorsTracersGet) {
59+
throw new IllegalStateException("Set cannot be called after any get call");
60+
}
61+
if (isGlobalInterceptorsTracersSet) {
62+
throw new IllegalStateException("Global interceptors and tracers are already set");
63+
}
64+
65+
if (clientInterceptorList != null) {
66+
clientInterceptors = Collections.unmodifiableList(new ArrayList<>(clientInterceptorList));
67+
}
68+
69+
if (serverInterceptorList != null) {
70+
serverInterceptors = Collections.unmodifiableList(new ArrayList<>(serverInterceptorList));
71+
}
72+
73+
if (serverStreamTracerFactoryList != null) {
74+
serverStreamTracerFactories =
75+
Collections.unmodifiableList(new ArrayList<>(serverStreamTracerFactoryList));
76+
}
77+
isGlobalInterceptorsTracersSet = true;
78+
}
79+
80+
/**
81+
* Returns the list of global {@link ClientInterceptor}. If not set, this returns am empty list.
82+
*/
83+
static synchronized List<ClientInterceptor> getClientInterceptors() {
84+
isGlobalInterceptorsTracersGet = true;
85+
return clientInterceptors;
86+
}
87+
88+
/** Returns list of global {@link ServerInterceptor}. If not set, this returns an empty list. */
89+
static synchronized List<ServerInterceptor> getServerInterceptors() {
90+
isGlobalInterceptorsTracersGet = true;
91+
return serverInterceptors;
92+
}
93+
94+
/**
95+
* Returns list of global {@link ServerStreamTracer.Factory}. If not set, this returns an empty
96+
* list.
97+
*/
98+
static synchronized List<ServerStreamTracer.Factory> getServerStreamTracerFactories() {
99+
isGlobalInterceptorsTracersGet = true;
100+
return serverStreamTracerFactories;
101+
}
102+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2022 The gRPC Authors
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 java.util.List;
20+
21+
/** Accessor to internal methods of {@link GlobalInterceptors}. */
22+
@Internal
23+
public final class InternalGlobalInterceptors {
24+
25+
public static void setInterceptorsTracers(
26+
List<ClientInterceptor> clientInterceptorList,
27+
List<ServerInterceptor> serverInterceptorList,
28+
List<ServerStreamTracer.Factory> serverStreamTracerFactoryList) {
29+
GlobalInterceptors.setInterceptorsTracers(
30+
clientInterceptorList, serverInterceptorList, serverStreamTracerFactoryList);
31+
}
32+
33+
public static List<ClientInterceptor> getClientInterceptors() {
34+
return GlobalInterceptors.getClientInterceptors();
35+
}
36+
37+
public static List<ServerInterceptor> getServerInterceptors() {
38+
return GlobalInterceptors.getServerInterceptors();
39+
}
40+
41+
public static List<ServerStreamTracer.Factory> getServerStreamTracerFactories() {
42+
return GlobalInterceptors.getServerStreamTracerFactories();
43+
}
44+
45+
private InternalGlobalInterceptors() {}
46+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright 2022 The gRPC Authors
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 static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.fail;
21+
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.List;
25+
import java.util.regex.Pattern;
26+
import org.junit.Test;
27+
28+
public class GlobalInterceptorsTest {
29+
30+
private final StaticTestingClassLoader classLoader =
31+
new StaticTestingClassLoader(
32+
getClass().getClassLoader(), Pattern.compile("io\\.grpc\\.[^.]+"));
33+
34+
@Test
35+
public void setInterceptorsTracers() throws Exception {
36+
Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSet.class.getName());
37+
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
38+
}
39+
40+
@Test
41+
public void setGlobalInterceptorsTracers_twice() throws Exception {
42+
Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSetTwice.class.getName());
43+
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
44+
}
45+
46+
@Test
47+
public void getBeforeSet_clientInterceptors() throws Exception {
48+
Class<?> runnable =
49+
classLoader.loadClass(
50+
StaticTestingClassLoaderGetBeforeSetClientInterceptor.class.getName());
51+
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
52+
}
53+
54+
@Test
55+
public void getBeforeSet_serverInterceptors() throws Exception {
56+
Class<?> runnable =
57+
classLoader.loadClass(
58+
StaticTestingClassLoaderGetBeforeSetServerInterceptor.class.getName());
59+
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
60+
}
61+
62+
@Test
63+
public void getBeforeSet_serverStreamTracerFactories() throws Exception {
64+
Class<?> runnable =
65+
classLoader.loadClass(
66+
StaticTestingClassLoaderGetBeforeSetServerStreamTracerFactory.class.getName());
67+
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
68+
}
69+
70+
// UsedReflectively
71+
public static final class StaticTestingClassLoaderSet implements Runnable {
72+
@Override
73+
public void run() {
74+
List<ClientInterceptor> clientInterceptorList =
75+
new ArrayList<>(Arrays.asList(new NoopClientInterceptor()));
76+
List<ServerInterceptor> serverInterceptorList =
77+
new ArrayList<>(Arrays.asList(new NoopServerInterceptor()));
78+
List<ServerStreamTracer.Factory> serverStreamTracerFactoryList =
79+
new ArrayList<>(
80+
Arrays.asList(
81+
new NoopServerStreamTracerFactory(), new NoopServerStreamTracerFactory()));
82+
83+
GlobalInterceptors.setInterceptorsTracers(
84+
clientInterceptorList, serverInterceptorList, serverStreamTracerFactoryList);
85+
86+
assertThat(GlobalInterceptors.getClientInterceptors()).isEqualTo(clientInterceptorList);
87+
assertThat(GlobalInterceptors.getServerInterceptors()).isEqualTo(serverInterceptorList);
88+
assertThat(GlobalInterceptors.getServerStreamTracerFactories())
89+
.isEqualTo(serverStreamTracerFactoryList);
90+
}
91+
}
92+
93+
public static final class StaticTestingClassLoaderSetTwice implements Runnable {
94+
@Override
95+
public void run() {
96+
GlobalInterceptors.setInterceptorsTracers(
97+
new ArrayList<>(Arrays.asList(new NoopClientInterceptor())),
98+
null,
99+
new ArrayList<>(Arrays.asList(new NoopServerStreamTracerFactory())));
100+
try {
101+
GlobalInterceptors.setInterceptorsTracers(
102+
null, new ArrayList<>(Arrays.asList(new NoopServerInterceptor())), null);
103+
fail("should have failed for calling setGlobalInterceptorsTracers() again");
104+
} catch (IllegalStateException e) {
105+
assertThat(e).hasMessageThat().isEqualTo("Global interceptors and tracers are already set");
106+
}
107+
}
108+
}
109+
110+
public static final class StaticTestingClassLoaderGetBeforeSetClientInterceptor
111+
implements Runnable {
112+
@Override
113+
public void run() {
114+
List<ClientInterceptor> clientInterceptors = GlobalInterceptors.getClientInterceptors();
115+
assertThat(clientInterceptors).isEmpty();
116+
117+
try {
118+
GlobalInterceptors.setInterceptorsTracers(
119+
new ArrayList<>(Arrays.asList(new NoopClientInterceptor())), null, null);
120+
fail("should have failed for invoking set call after get is already called");
121+
} catch (IllegalStateException e) {
122+
assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call");
123+
}
124+
}
125+
}
126+
127+
public static final class StaticTestingClassLoaderGetBeforeSetServerInterceptor
128+
implements Runnable {
129+
@Override
130+
public void run() {
131+
List<ServerInterceptor> serverInterceptors = GlobalInterceptors.getServerInterceptors();
132+
assertThat(serverInterceptors).isEmpty();
133+
134+
try {
135+
GlobalInterceptors.setInterceptorsTracers(
136+
null, new ArrayList<>(Arrays.asList(new NoopServerInterceptor())), null);
137+
fail("should have failed for invoking set call after get is already called");
138+
} catch (IllegalStateException e) {
139+
assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call");
140+
}
141+
}
142+
}
143+
144+
public static final class StaticTestingClassLoaderGetBeforeSetServerStreamTracerFactory
145+
implements Runnable {
146+
@Override
147+
public void run() {
148+
List<ServerStreamTracer.Factory> serverStreamTracerFactories =
149+
GlobalInterceptors.getServerStreamTracerFactories();
150+
assertThat(serverStreamTracerFactories).isEmpty();
151+
152+
try {
153+
GlobalInterceptors.setInterceptorsTracers(
154+
null, null, new ArrayList<>(Arrays.asList(new NoopServerStreamTracerFactory())));
155+
fail("should have failed for invoking set call after get is already called");
156+
} catch (IllegalStateException e) {
157+
assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call");
158+
}
159+
}
160+
}
161+
162+
private static class NoopClientInterceptor implements ClientInterceptor {
163+
@Override
164+
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
165+
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
166+
return next.newCall(method, callOptions);
167+
}
168+
}
169+
170+
private static class NoopServerInterceptor implements ServerInterceptor {
171+
@Override
172+
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
173+
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
174+
return next.startCall(call, headers);
175+
}
176+
}
177+
178+
private static class NoopServerStreamTracerFactory extends ServerStreamTracer.Factory {
179+
@Override
180+
public ServerStreamTracer newServerStreamTracer(String fullMethodName, Metadata headers) {
181+
throw new UnsupportedOperationException();
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)