Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

Commit 4c3837a

Browse files
Merge pull request #21 from garrettjonesgoogle/master
Creating ApiCallableBuilder
2 parents f587a89 + 0faf83b commit 4c3837a

3 files changed

Lines changed: 505 additions & 169 deletions

File tree

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
/*
2+
* Copyright 2015, Google Inc.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are
7+
* met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
* * Redistributions in binary form must reproduce the above
12+
* copyright notice, this list of conditions and the following disclaimer
13+
* in the documentation and/or other materials provided with the
14+
* distribution.
15+
* * Neither the name of Google Inc. nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
package com.google.api.gax.grpc;
33+
34+
import com.google.api.gax.core.ConnectionSettings;
35+
import com.google.api.gax.core.RetryParams;
36+
import com.google.common.collect.Lists;
37+
import com.google.common.collect.Sets;
38+
import com.google.common.util.concurrent.MoreExecutors;
39+
40+
import io.grpc.ClientInterceptor;
41+
import io.grpc.ManagedChannel;
42+
import io.grpc.Status;
43+
import io.grpc.auth.ClientAuthInterceptor;
44+
import io.grpc.netty.NegotiationType;
45+
import io.grpc.netty.NettyChannelBuilder;
46+
47+
import java.io.IOException;
48+
import java.util.HashSet;
49+
import java.util.List;
50+
import java.util.Set;
51+
import java.util.concurrent.Executor;
52+
import java.util.concurrent.ScheduledExecutorService;
53+
import java.util.concurrent.ScheduledThreadPoolExecutor;
54+
55+
// TODO(pongad): Don't close the channel if the user gives one to us
56+
/**
57+
* A settings class to configure API method calls for either a single method or a
58+
* whole service.
59+
*
60+
* A note on channels: whichever service API class that this instance of ServiceApiSettings
61+
* is passed to will call shutdown() on the channel provided by {@link getChannel}.
62+
* Setting a channel is intended for use by unit tests to override the channel,
63+
* and should not be used in production.
64+
*/
65+
public class ApiCallSettings {
66+
67+
private ChannelProvider channelProvider;
68+
private ExecutorProvider executorProvider;
69+
70+
private Set<Status.Code> defaultRetryableCodes = null;
71+
private Set<Status.Code> retryableCodes = null;
72+
73+
private RetryParams defaultRetryParams = null;
74+
private RetryParams retryParams = null;
75+
76+
public static final int DEFAULT_EXECUTOR_THREADS = 4;
77+
78+
/**
79+
* Constructs an instance of ApiCallSettings.
80+
*/
81+
public ApiCallSettings() {
82+
channelProvider = new ChannelProvider() {
83+
@Override
84+
public ManagedChannel getChannel(Executor executor) {
85+
throw new RuntimeException("No Channel or ConnectionSettings provided.");
86+
}
87+
88+
@Override
89+
public boolean isOverridden() {
90+
return false;
91+
}
92+
};
93+
executorProvider = new ExecutorProvider() {
94+
private ScheduledExecutorService executor = null;
95+
@Override
96+
public ScheduledExecutorService getExecutor() {
97+
if (executor != null) {
98+
return executor;
99+
}
100+
executor = MoreExecutors.getExitingScheduledExecutorService(
101+
new ScheduledThreadPoolExecutor(DEFAULT_EXECUTOR_THREADS));
102+
return executor;
103+
}
104+
105+
@Override
106+
public boolean isOverridden() {
107+
return false;
108+
}
109+
};
110+
retryableCodes = new HashSet<>();
111+
}
112+
113+
private interface ChannelProvider {
114+
ManagedChannel getChannel(Executor executor) throws IOException;
115+
boolean isOverridden();
116+
}
117+
118+
/**
119+
* Sets a channel for this ApiCallSettings to use. This prevents a channel
120+
* from being created.
121+
*
122+
* See class documentation for more details on channels.
123+
*/
124+
public ApiCallSettings provideChannelWith(final ManagedChannel channel) {
125+
channelProvider = new ChannelProvider() {
126+
@Override
127+
public ManagedChannel getChannel(Executor executor) {
128+
return channel;
129+
}
130+
131+
@Override
132+
public boolean isOverridden() {
133+
return true;
134+
}
135+
};
136+
return this;
137+
}
138+
139+
/**
140+
* Provides the connection settings necessary to create a channel.
141+
*/
142+
public ApiCallSettings provideChannelWith(final ConnectionSettings settings) {
143+
channelProvider = new ChannelProvider() {
144+
private ManagedChannel channel = null;
145+
@Override
146+
public ManagedChannel getChannel(Executor executor) throws IOException {
147+
if (channel != null) {
148+
return channel;
149+
}
150+
151+
List<ClientInterceptor> interceptors = Lists.newArrayList();
152+
interceptors.add(new ClientAuthInterceptor(settings.getCredentials(), executor));
153+
154+
channel = NettyChannelBuilder.forAddress(settings.getServiceAddress(), settings.getPort())
155+
.negotiationType(NegotiationType.TLS)
156+
.intercept(interceptors)
157+
.build();
158+
return channel;
159+
}
160+
161+
@Override
162+
public boolean isOverridden() {
163+
return true;
164+
}
165+
};
166+
return this;
167+
}
168+
169+
/**
170+
* The channel used to send requests to the service.
171+
*
172+
* If no channel was set, a default channel will be instantiated, using
173+
* the connection settings provided.
174+
*
175+
* See class documentation for more details on channels.
176+
*/
177+
public ManagedChannel getChannel() throws IOException {
178+
return channelProvider.getChannel(getExecutor());
179+
}
180+
181+
/**
182+
* Returns true if either a channel was set or connection settings were
183+
* provided to create a channel.
184+
*/
185+
public boolean isChannelOverridden() {
186+
return channelProvider.isOverridden();
187+
}
188+
189+
private interface ExecutorProvider {
190+
ScheduledExecutorService getExecutor();
191+
boolean isOverridden();
192+
}
193+
194+
/**
195+
* Sets the executor to use for channels, retries, and bundling.
196+
*
197+
* It is up to the user to terminate the {@code Executor} when it is no longer needed.
198+
*/
199+
public ApiCallSettings setExecutor(final ScheduledExecutorService executor) {
200+
executorProvider = new ExecutorProvider() {
201+
@Override
202+
public ScheduledExecutorService getExecutor() {
203+
return executor;
204+
}
205+
206+
@Override
207+
public boolean isOverridden() {
208+
return true;
209+
}
210+
};
211+
return this;
212+
}
213+
214+
/**
215+
* The executor to be used by the client.
216+
*
217+
* If no executor was set, a default {@link java.util.concurrent.ScheduledThreadPoolExecutor}
218+
* with {@link DEFAULT_EXECUTOR_THREADS} will be instantiated.
219+
*
220+
* The default executor is guaranteed to not prevent JVM from normally exiting,
221+
* but may wait for up to 120 seconds after all non-daemon threads exit to give received tasks
222+
* time to complete.
223+
*
224+
* If this behavior is not desirable, the user may specify a custom {@code Executor}.
225+
*/
226+
public ScheduledExecutorService getExecutor() {
227+
return executorProvider.getExecutor();
228+
}
229+
230+
/**
231+
* Returns true if an executor was set.
232+
*/
233+
public boolean isExecutorOverridden() {
234+
return executorProvider.isOverridden();
235+
}
236+
237+
/**
238+
* Sets the defaults to use for retryable codes and retry params.
239+
*
240+
* If setRetryableCodes is not called, the default retryableCodes provided here will be returned
241+
* from getRetryableCodes. Likewise, if setRetryParams is not called, the default retryParams
242+
* provided here will be returned from getRetryParams.
243+
*/
244+
public void setRetryDefaults(Set<Status.Code> retryableCodes, RetryParams retryParams) {
245+
this.defaultRetryableCodes = retryableCodes;
246+
this.retryParams = retryParams;
247+
}
248+
249+
/**
250+
* Sets the retryable codes.
251+
*/
252+
public ApiCallSettings setRetryableCodes(Set<Status.Code> retryableCodes) {
253+
this.retryableCodes = retryableCodes;
254+
return this;
255+
}
256+
257+
/**
258+
* Sets the retryable codes.
259+
*/
260+
public ApiCallSettings setRetryableCodes(Status.Code... codes) {
261+
this.retryableCodes = Sets.newHashSet(codes);
262+
return this;
263+
}
264+
265+
/**
266+
* Gets the retryable codes that were set previously, or if they were not, then returns
267+
* the default retryable codes provided previously.
268+
*/
269+
public Set<Status.Code> getRetryableCodes() {
270+
if (isRetryableCodesOverridden()) {
271+
return retryableCodes;
272+
} else {
273+
return defaultRetryableCodes;
274+
}
275+
}
276+
277+
/**
278+
* Returns true if the retryable codes were set.
279+
*/
280+
public boolean isRetryableCodesOverridden() {
281+
return retryableCodes != null;
282+
}
283+
284+
/**
285+
* Sets the retry params.
286+
*/
287+
public ApiCallSettings setRetryParams(RetryParams retryParams) {
288+
this.retryParams = retryParams;
289+
return this;
290+
}
291+
292+
/**
293+
* Returns the retry params that were set previously, or if they were not, then returns
294+
* the default retry params provided previously.
295+
*/
296+
public RetryParams getRetryParams() {
297+
if (isRetryParamsOverridden()) {
298+
return retryParams;
299+
} else {
300+
return defaultRetryParams;
301+
}
302+
}
303+
304+
/**
305+
* Returns true if the retry params were set.
306+
*/
307+
public boolean isRetryParamsOverridden() {
308+
return retryParams != null;
309+
}
310+
}

0 commit comments

Comments
 (0)