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, with the default {@code CallOptions}.
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 an absolute deadline.
106    *
107    * <p>This is mostly used for propagating an existing deadline. {@link #withDeadlineAfter} is the
108    * recommended way of setting a new deadline,
109    *
110    * @since 1.0.0
111    * @param deadline the deadline or {@code null} for unsetting the deadline.
112    */
withDeadline(@ullable Deadline deadline)113   public final S withDeadline(@Nullable Deadline deadline) {
114     return build(channel, callOptions.withDeadline(deadline));
115   }
116 
117   /**
118    * Returns a new stub with a deadline that is after the given {@code duration} from now.
119    *
120    * @since 1.0.0
121    * @see CallOptions#withDeadlineAfter
122    */
withDeadlineAfter(long duration, TimeUnit unit)123   public final S withDeadlineAfter(long duration, TimeUnit unit) {
124     return build(channel, callOptions.withDeadlineAfter(duration, unit));
125   }
126 
127   /**
128    * Returns a new stub with the given executor that is to be used instead of the default one
129    * specified with {@link ManagedChannelBuilder#executor}. Note that setting this option may not
130    * take effect for blocking calls.
131    *
132    * @since 1.8.0
133    */
withExecutor(Executor executor)134   public final S withExecutor(Executor executor) {
135     return build(channel, callOptions.withExecutor(executor));
136   }
137 
138   /**
139    *  Set's the compressor name to use for the call.  It is the responsibility of the application
140    *  to make sure the server supports decoding the compressor picked by the client.  To be clear,
141    *  this is the compressor used by the stub to compress messages to the server.  To get
142    *  compressed responses from the server, set the appropriate {@link io.grpc.DecompressorRegistry}
143    *  on the {@link io.grpc.ManagedChannelBuilder}.
144    *
145    * @since 1.0.0
146    * @param compressorName the name (e.g. "gzip") of the compressor to use.
147    */
148   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1704")
withCompression(String compressorName)149   public final S withCompression(String compressorName) {
150     return build(channel, callOptions.withCompression(compressorName));
151   }
152 
153   /**
154    * Returns a new stub that uses the given channel.
155    *
156    * <p>This method is vestigial and is unlikely to be useful.  Instead, users should prefer to
157    * use {@link #withInterceptors}.
158    *
159    * @since 1.0.0
160    */
161   @Deprecated // use withInterceptors() instead
withChannel(Channel newChannel)162   public final S withChannel(Channel newChannel) {
163     return build(newChannel, callOptions);
164   }
165 
166   /**
167    * Sets a custom option to be passed to client interceptors on the channel
168    * {@link io.grpc.ClientInterceptor} via the CallOptions parameter.
169    *
170    * @since 1.0.0
171    * @param key the option being set
172    * @param value the value for the key
173    */
174   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1869")
withOption(CallOptions.Key<T> key, T value)175   public final <T> S withOption(CallOptions.Key<T> key, T value) {
176     return build(channel, callOptions.withOption(key, value));
177   }
178 
179   /**
180    * Returns a new stub that has the given interceptors attached to the underlying channel.
181    *
182    * @since 1.0.0
183    */
withInterceptors(ClientInterceptor... interceptors)184   public final S withInterceptors(ClientInterceptor... interceptors) {
185     return build(ClientInterceptors.intercept(channel, interceptors), callOptions);
186   }
187 
188   /**
189    * Returns a new stub that uses the given call credentials.
190    *
191    * @since 1.0.0
192    */
withCallCredentials(CallCredentials credentials)193   public final S withCallCredentials(CallCredentials credentials) {
194     return build(channel, callOptions.withCallCredentials(credentials));
195   }
196 
197   /**
198    * Returns a new stub that uses the 'wait for ready' call option.
199    *
200    * @since 1.1.0
201    */
withWaitForReady()202   public final S withWaitForReady() {
203     return build(channel, callOptions.withWaitForReady());
204   }
205 
206   /**
207    * Returns a new stub that limits the maximum acceptable message size from a remote peer.
208    *
209    * <p>If unset, the {@link ManagedChannelBuilder#maxInboundMessageSize(int)} limit is used.
210    *
211    * @since 1.1.0
212    */
213   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563")
withMaxInboundMessageSize(int maxSize)214   public final S withMaxInboundMessageSize(int maxSize) {
215     return build(channel, callOptions.withMaxInboundMessageSize(maxSize));
216   }
217 
218   /**
219    * Returns a new stub that limits the maximum acceptable message size to send a remote peer.
220    *
221    * @since 1.1.0
222    */
223   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563")
withMaxOutboundMessageSize(int maxSize)224   public final S withMaxOutboundMessageSize(int maxSize) {
225     return build(channel, callOptions.withMaxOutboundMessageSize(maxSize));
226   }
227 }
228