• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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.stub;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import io.grpc.CallCredentials;
22 import io.grpc.CallOptions;
23 import io.grpc.Channel;
24 import io.grpc.ClientInterceptor;
25 import io.grpc.ClientInterceptors;
26 import io.grpc.Deadline;
27 import io.grpc.ExperimentalApi;
28 import io.grpc.ManagedChannelBuilder;
29 import java.util.concurrent.Executor;
30 import java.util.concurrent.TimeUnit;
31 import javax.annotation.CheckReturnValue;
32 import javax.annotation.Nullable;
33 import javax.annotation.concurrent.ThreadSafe;
34 
35 /**
36  * Common base type for stub implementations. Stub configuration is immutable; changing the
37  * configuration returns a new stub with updated configuration. Changing the configuration is cheap
38  * and may be done before every RPC, such as would be common when using {@link #withDeadlineAfter}.
39  *
40  * <p>Configuration is stored in {@link CallOptions} and is passed to the {@link Channel} when
41  * performing an RPC.
42  *
43  * <p>DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder
44  * to create a real channel suitable for testing. It is also possible to mock Channel instead.
45  *
46  * @since 1.0.0
47  * @param <S> the concrete type of this stub.
48  */
49 @ThreadSafe
50 @CheckReturnValue
51 public abstract class AbstractStub<S extends AbstractStub<S>> {
52   private final Channel channel;
53   private final CallOptions callOptions;
54 
55   /**
56    * Constructor for use by subclasses, with the default {@code CallOptions}.
57    *
58    * @since 1.0.0
59    * @param channel the channel that this stub will use to do communications
60    */
AbstractStub(Channel channel)61   protected AbstractStub(Channel channel) {
62     this(channel, CallOptions.DEFAULT);
63   }
64 
65   /**
66    * Constructor for use by subclasses.
67    *
68    * @since 1.0.0
69    * @param channel the channel that this stub will use to do communications
70    * @param callOptions the runtime call options to be applied to every call on this stub
71    */
AbstractStub(Channel channel, CallOptions callOptions)72   protected AbstractStub(Channel channel, CallOptions callOptions) {
73     this.channel = checkNotNull(channel, "channel");
74     this.callOptions = checkNotNull(callOptions, "callOptions");
75   }
76 
77   /**
78    * The underlying channel of the stub.
79    *
80    * @since 1.0.0
81    */
getChannel()82   public final Channel getChannel() {
83     return channel;
84   }
85 
86   /**
87    * The {@code CallOptions} of the stub.
88    *
89    * @since 1.0.0
90    */
getCallOptions()91   public final CallOptions getCallOptions() {
92     return callOptions;
93   }
94 
95   /**
96    * Returns a new stub with the given channel for the provided method configurations.
97    *
98    * @since 1.0.0
99    * @param channel the channel that this stub will use to do communications
100    * @param callOptions the runtime call options to be applied to every call on this stub
101    */
build(Channel channel, CallOptions callOptions)102   protected abstract S build(Channel channel, CallOptions callOptions);
103 
104   /**
105    * Returns a new stub with the given channel for the provided method configurations.
106    *
107    * @since 1.26.0
108    * @param factory the factory to create a stub
109    * @param channel the channel that this stub will use to do communications
110    */
newStub( StubFactory<T> factory, Channel channel)111   public static <T extends AbstractStub<T>> T newStub(
112       StubFactory<T> factory, Channel channel) {
113     return newStub(factory, channel, CallOptions.DEFAULT);
114   }
115 
116   /**
117    * Returns a new stub with the given channel for the provided method configurations.
118    *
119    * @since 1.26.0
120    * @param factory the factory to create a stub
121    * @param channel the channel that this stub will use to do communications
122    * @param callOptions the runtime call options to be applied to every call on this stub
123    */
newStub( StubFactory<T> factory, Channel channel, CallOptions callOptions)124   public static <T extends AbstractStub<T>> T newStub(
125       StubFactory<T> factory, Channel channel, CallOptions callOptions) {
126     return factory.newStub(channel, callOptions);
127   }
128 
129   /**
130    * Returns a new stub with an absolute deadline.
131    *
132    * <p>This is mostly used for propagating an existing deadline. {@link #withDeadlineAfter} is the
133    * recommended way of setting a new deadline,
134    *
135    * @since 1.0.0
136    * @param deadline the deadline or {@code null} for unsetting the deadline.
137    */
withDeadline(@ullable Deadline deadline)138   public final S withDeadline(@Nullable Deadline deadline) {
139     return build(channel, callOptions.withDeadline(deadline));
140   }
141 
142   /**
143    * Returns a new stub with a deadline that is after the given {@code duration} from now.
144    *
145    * @since 1.0.0
146    * @see CallOptions#withDeadlineAfter
147    */
withDeadlineAfter(long duration, TimeUnit unit)148   public final S withDeadlineAfter(long duration, TimeUnit unit) {
149     return build(channel, callOptions.withDeadlineAfter(duration, unit));
150   }
151 
152   /**
153    * Returns a new stub with the given executor that is to be used instead of the default one
154    * specified with {@link ManagedChannelBuilder#executor}. Note that setting this option may not
155    * take effect for blocking calls.
156    *
157    * @since 1.8.0
158    */
withExecutor(Executor executor)159   public final S withExecutor(Executor executor) {
160     return build(channel, callOptions.withExecutor(executor));
161   }
162 
163   /**
164    *  Set's the compressor name to use for the call.  It is the responsibility of the application
165    *  to make sure the server supports decoding the compressor picked by the client.  To be clear,
166    *  this is the compressor used by the stub to compress messages to the server.
167    *
168    * @since 1.0.0
169    * @param compressorName the name (e.g. "gzip") of the compressor to use.
170    */
withCompression(String compressorName)171   public final S withCompression(String compressorName) {
172     return build(channel, callOptions.withCompression(compressorName));
173   }
174 
175   /**
176    * Returns a new stub that uses the given channel.
177    *
178    * <p>This method is vestigial and is unlikely to be useful.  Instead, users should prefer to
179    * use {@link #withInterceptors}.
180    *
181    * @since 1.0.0
182    */
183   @Deprecated // use withInterceptors() instead
withChannel(Channel newChannel)184   public final S withChannel(Channel newChannel) {
185     return build(newChannel, callOptions);
186   }
187 
188   /**
189    * Sets a custom option to be passed to client interceptors on the channel
190    * {@link io.grpc.ClientInterceptor} via the CallOptions parameter.
191    *
192    * @since 1.0.0
193    * @param key the option being set
194    * @param value the value for the key
195    */
196   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1869")
withOption(CallOptions.Key<T> key, T value)197   public final <T> S withOption(CallOptions.Key<T> key, T value) {
198     return build(channel, callOptions.withOption(key, value));
199   }
200 
201   /**
202    * Returns a new stub that has the given interceptors attached to the underlying channel.
203    *
204    * @since 1.0.0
205    */
withInterceptors(ClientInterceptor... interceptors)206   public final S withInterceptors(ClientInterceptor... interceptors) {
207     return build(ClientInterceptors.intercept(channel, interceptors), callOptions);
208   }
209 
210   /**
211    * Returns a new stub that uses the given call credentials.
212    *
213    * @since 1.0.0
214    */
withCallCredentials(CallCredentials credentials)215   public final S withCallCredentials(CallCredentials credentials) {
216     return build(channel, callOptions.withCallCredentials(credentials));
217   }
218 
219   /**
220    * Returns a new stub that uses
221    * <a href="https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md">'wait for ready'</a>
222    * for the call. Wait-for-ready queues the RPC until a connection is available. This may
223    * dramatically increase the latency of the RPC, but avoids failing "unnecessarily." The default
224    * queues the RPC until an attempt to connect has completed, but fails RPCs without sending them
225    * if unable to connect.
226    *
227    * @since 1.1.0
228    */
withWaitForReady()229   public final S withWaitForReady() {
230     return build(channel, callOptions.withWaitForReady());
231   }
232 
233   /**
234    * Returns a new stub that limits the maximum acceptable message size from a remote peer.
235    *
236    * <p>If unset, the {@link ManagedChannelBuilder#maxInboundMessageSize(int)} limit is used.
237    *
238    * @since 1.1.0
239    */
240   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563")
withMaxInboundMessageSize(int maxSize)241   public final S withMaxInboundMessageSize(int maxSize) {
242     return build(channel, callOptions.withMaxInboundMessageSize(maxSize));
243   }
244 
245   /**
246    * Returns a new stub that limits the maximum acceptable message size to send a remote peer.
247    *
248    * @since 1.1.0
249    */
250   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563")
withMaxOutboundMessageSize(int maxSize)251   public final S withMaxOutboundMessageSize(int maxSize) {
252     return build(channel, callOptions.withMaxOutboundMessageSize(maxSize));
253   }
254 
255   /**
256    * A factory class for stub.
257    *
258    * @since 1.26.0
259    */
260   public interface StubFactory<T extends AbstractStub<T>> {
newStub(Channel channel, CallOptions callOptions)261     T newStub(Channel channel, CallOptions callOptions);
262   }
263 }
264