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