• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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.inprocess;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 
22 import com.google.errorprone.annotations.DoNotCall;
23 import io.grpc.ChannelCredentials;
24 import io.grpc.ChannelLogger;
25 import io.grpc.ExperimentalApi;
26 import io.grpc.Internal;
27 import io.grpc.ManagedChannelBuilder;
28 import io.grpc.internal.AbstractManagedChannelImplBuilder;
29 import io.grpc.internal.ClientTransportFactory;
30 import io.grpc.internal.ConnectionClientTransport;
31 import io.grpc.internal.GrpcUtil;
32 import io.grpc.internal.ManagedChannelImplBuilder;
33 import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
34 import io.grpc.internal.SharedResourceHolder;
35 import java.net.SocketAddress;
36 import java.util.concurrent.ScheduledExecutorService;
37 import java.util.concurrent.TimeUnit;
38 import javax.annotation.Nullable;
39 
40 /**
41  * Builder for a channel that issues in-process requests. Clients identify the in-process server by
42  * its name.
43  *
44  * <p>The channel is intended to be fully-featured, high performance, and useful in testing.
45  *
46  * <p>For usage examples, see {@link InProcessServerBuilder}.
47  */
48 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1783")
49 public final class InProcessChannelBuilder extends
50     AbstractManagedChannelImplBuilder<InProcessChannelBuilder> {
51   /**
52    * Create a channel builder that will connect to the server with the given name.
53    *
54    * @param name the identity of the server to connect to
55    * @return a new builder
56    */
forName(String name)57   public static InProcessChannelBuilder forName(String name) {
58     return forAddress(new InProcessSocketAddress(checkNotNull(name, "name")));
59   }
60 
61   /**
62    * Create a channel builder that will connect to the server referenced by the given target URI.
63    * Only intended for use with a custom name resolver.
64    *
65    * @param target the identity of the server to connect to
66    * @return a new builder
67    */
forTarget(String target)68   public static InProcessChannelBuilder forTarget(String target) {
69     return new InProcessChannelBuilder(null, checkNotNull(target, "target"));
70   }
71 
72   /**
73    * Create a channel builder that will connect to the server referenced by the given address.
74    *
75    * @param address the address of the server to connect to
76    * @return a new builder
77    */
forAddress(SocketAddress address)78   public static InProcessChannelBuilder forAddress(SocketAddress address) {
79     return new InProcessChannelBuilder(checkNotNull(address, "address"), null);
80   }
81 
82   /**
83    * Always fails.  Call {@link #forName} instead.
84    */
85   @DoNotCall("Unsupported. Use forName() instead")
forAddress(String name, int port)86   public static InProcessChannelBuilder forAddress(String name, int port) {
87     throw new UnsupportedOperationException("call forName() instead");
88   }
89 
90   private final ManagedChannelImplBuilder managedChannelImplBuilder;
91   private ScheduledExecutorService scheduledExecutorService;
92   private int maxInboundMetadataSize = Integer.MAX_VALUE;
93   private boolean transportIncludeStatusCause = false;
94 
InProcessChannelBuilder(@ullable SocketAddress directAddress, @Nullable String target)95   private InProcessChannelBuilder(@Nullable SocketAddress directAddress, @Nullable String target) {
96 
97     final class InProcessChannelTransportFactoryBuilder implements ClientTransportFactoryBuilder {
98       @Override
99       public ClientTransportFactory buildClientTransportFactory() {
100         return buildTransportFactory();
101       }
102     }
103 
104     if (directAddress != null) {
105       managedChannelImplBuilder = new ManagedChannelImplBuilder(directAddress, "localhost",
106           new InProcessChannelTransportFactoryBuilder(), null);
107     } else {
108       managedChannelImplBuilder = new ManagedChannelImplBuilder(target,
109           new InProcessChannelTransportFactoryBuilder(), null);
110     }
111 
112     // In-process transport should not record its traffic to the stats module.
113     // https://github.com/grpc/grpc-java/issues/2284
114     managedChannelImplBuilder.setStatsRecordStartedRpcs(false);
115     managedChannelImplBuilder.setStatsRecordFinishedRpcs(false);
116     managedChannelImplBuilder.setStatsRecordRetryMetrics(false);
117 
118     // By default, In-process transport should not be retriable as that leaks memory.  Since
119     // there is no wire, bytes aren't calculated so buffer limit isn't respected
120     managedChannelImplBuilder.disableRetry();
121   }
122 
123   @Internal
124   @Override
delegate()125   protected ManagedChannelBuilder<?> delegate() {
126     return managedChannelImplBuilder;
127   }
128 
129   @Override
maxInboundMessageSize(int max)130   public InProcessChannelBuilder maxInboundMessageSize(int max) {
131     // TODO(carl-mastrangelo): maybe throw an exception since this not enforced?
132     return super.maxInboundMessageSize(max);
133   }
134 
135   /**
136    * Does nothing.
137    */
138   @Override
useTransportSecurity()139   public InProcessChannelBuilder useTransportSecurity() {
140     return this;
141   }
142 
143   /**
144    * Does nothing.
145    */
146   @Override
usePlaintext()147   public InProcessChannelBuilder usePlaintext() {
148     return this;
149   }
150 
151   /** Does nothing. */
152   @Override
keepAliveTime(long keepAliveTime, TimeUnit timeUnit)153   public InProcessChannelBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
154     return this;
155   }
156 
157   /** Does nothing. */
158   @Override
keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit)159   public InProcessChannelBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
160     return this;
161   }
162 
163   /** Does nothing. */
164   @Override
keepAliveWithoutCalls(boolean enable)165   public InProcessChannelBuilder keepAliveWithoutCalls(boolean enable) {
166     return this;
167   }
168 
169   /**
170    * Provides a custom scheduled executor service.
171    *
172    * <p>It's an optional parameter. If the user has not provided a scheduled executor service when
173    * the channel is built, the builder will use a static cached thread pool.
174    *
175    * @return this
176    *
177    * @since 1.11.0
178    */
scheduledExecutorService( ScheduledExecutorService scheduledExecutorService)179   public InProcessChannelBuilder scheduledExecutorService(
180       ScheduledExecutorService scheduledExecutorService) {
181     this.scheduledExecutorService =
182         checkNotNull(scheduledExecutorService, "scheduledExecutorService");
183     return this;
184   }
185 
186   /**
187    * Sets the maximum size of metadata allowed to be received. {@code Integer.MAX_VALUE} disables
188    * the enforcement. Defaults to no limit ({@code Integer.MAX_VALUE}).
189    *
190    * <p>There is potential for performance penalty when this setting is enabled, as the Metadata
191    * must actually be serialized. Since the current implementation of Metadata pre-serializes, it's
192    * currently negligible. But Metadata is free to change its implementation.
193    *
194    * @param bytes the maximum size of received metadata
195    * @return this
196    * @throws IllegalArgumentException if bytes is non-positive
197    * @since 1.17.0
198    */
199   @Override
maxInboundMetadataSize(int bytes)200   public InProcessChannelBuilder maxInboundMetadataSize(int bytes) {
201     checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0");
202     this.maxInboundMetadataSize = bytes;
203     return this;
204   }
205 
206   /**
207    * Sets whether to include the cause with the status that is propagated
208    * forward from the InProcessTransport. This was added to make debugging failing
209    * tests easier by showing the cause of the status.
210    *
211    * <p>By default, this is set to false.
212    * A default value of false maintains consistency with other transports which strip causal
213    * information from the status to avoid leaking information to untrusted clients, and
214    * to avoid sharing language-specific information with the client.
215    * For the in-process implementation, this is not a concern.
216    *
217    * @param enable whether to include cause in status
218    * @return this
219    */
propagateCauseWithStatus(boolean enable)220   public InProcessChannelBuilder propagateCauseWithStatus(boolean enable) {
221     this.transportIncludeStatusCause = enable;
222     return this;
223   }
224 
buildTransportFactory()225   ClientTransportFactory buildTransportFactory() {
226     return new InProcessClientTransportFactory(
227         scheduledExecutorService, maxInboundMetadataSize, transportIncludeStatusCause);
228   }
229 
setStatsEnabled(boolean value)230   void setStatsEnabled(boolean value) {
231     this.managedChannelImplBuilder.setStatsEnabled(value);
232   }
233 
234   /**
235    * Creates InProcess transports. Exposed for internal use, as it should be private.
236    */
237   static final class InProcessClientTransportFactory implements ClientTransportFactory {
238     private final ScheduledExecutorService timerService;
239     private final boolean useSharedTimer;
240     private final int maxInboundMetadataSize;
241     private boolean closed;
242     private final boolean includeCauseWithStatus;
243 
InProcessClientTransportFactory( @ullable ScheduledExecutorService scheduledExecutorService, int maxInboundMetadataSize, boolean includeCauseWithStatus)244     private InProcessClientTransportFactory(
245         @Nullable ScheduledExecutorService scheduledExecutorService,
246         int maxInboundMetadataSize, boolean includeCauseWithStatus) {
247       useSharedTimer = scheduledExecutorService == null;
248       timerService = useSharedTimer
249           ? SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE) : scheduledExecutorService;
250       this.maxInboundMetadataSize = maxInboundMetadataSize;
251       this.includeCauseWithStatus = includeCauseWithStatus;
252     }
253 
254     @Override
newClientTransport( SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger)255     public ConnectionClientTransport newClientTransport(
256         SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger) {
257       if (closed) {
258         throw new IllegalStateException("The transport factory is closed.");
259       }
260       // TODO(carl-mastrangelo): Pass channelLogger in.
261       return new InProcessTransport(
262           addr, maxInboundMetadataSize, options.getAuthority(), options.getUserAgent(),
263           options.getEagAttributes(), includeCauseWithStatus);
264     }
265 
266     @Override
getScheduledExecutorService()267     public ScheduledExecutorService getScheduledExecutorService() {
268       return timerService;
269     }
270 
271     @Override
swapChannelCredentials(ChannelCredentials channelCreds)272     public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials channelCreds) {
273       return null;
274     }
275 
276     @Override
close()277     public void close() {
278       if (closed) {
279         return;
280       }
281       closed = true;
282       if (useSharedTimer) {
283         SharedResourceHolder.release(GrpcUtil.TIMER_SERVICE, timerService);
284       }
285     }
286   }
287 }
288