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