• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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.internal;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 
22 import com.google.common.annotations.VisibleForTesting;
23 import com.google.common.util.concurrent.MoreExecutors;
24 import com.google.errorprone.annotations.DoNotCall;
25 import io.grpc.BinaryLog;
26 import io.grpc.BindableService;
27 import io.grpc.CompressorRegistry;
28 import io.grpc.Context;
29 import io.grpc.Deadline;
30 import io.grpc.DecompressorRegistry;
31 import io.grpc.HandlerRegistry;
32 import io.grpc.InternalChannelz;
33 import io.grpc.InternalGlobalInterceptors;
34 import io.grpc.Server;
35 import io.grpc.ServerBuilder;
36 import io.grpc.ServerCallExecutorSupplier;
37 import io.grpc.ServerInterceptor;
38 import io.grpc.ServerMethodDefinition;
39 import io.grpc.ServerServiceDefinition;
40 import io.grpc.ServerStreamTracer;
41 import io.grpc.ServerTransportFilter;
42 import java.io.File;
43 import java.lang.reflect.InvocationTargetException;
44 import java.lang.reflect.Method;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.concurrent.Executor;
49 import java.util.concurrent.TimeUnit;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52 import javax.annotation.Nullable;
53 
54 /**
55  * Default builder for {@link io.grpc.Server} instances, for usage in Transport implementations.
56  */
57 public final class ServerImplBuilder extends ServerBuilder<ServerImplBuilder> {
58 
59   private static final Logger log = Logger.getLogger(ServerImplBuilder.class.getName());
60 
61   @DoNotCall("ClientTransportServersBuilder is required, use a constructor")
forPort(int port)62   public static ServerBuilder<?> forPort(int port) {
63     throw new UnsupportedOperationException(
64         "ClientTransportServersBuilder is required, use a constructor");
65   }
66 
67   // defaults
68   private static final ObjectPool<? extends Executor> DEFAULT_EXECUTOR_POOL =
69       SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR);
70   private static final HandlerRegistry DEFAULT_FALLBACK_REGISTRY = new DefaultFallbackRegistry();
71   private static final DecompressorRegistry DEFAULT_DECOMPRESSOR_REGISTRY =
72       DecompressorRegistry.getDefaultInstance();
73   private static final CompressorRegistry DEFAULT_COMPRESSOR_REGISTRY =
74       CompressorRegistry.getDefaultInstance();
75   private static final long DEFAULT_HANDSHAKE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(120);
76 
77   // mutable state
78   final InternalHandlerRegistry.Builder registryBuilder =
79       new InternalHandlerRegistry.Builder();
80   final List<ServerTransportFilter> transportFilters = new ArrayList<>();
81   final List<ServerInterceptor> interceptors = new ArrayList<>();
82   private final List<ServerStreamTracer.Factory> streamTracerFactories = new ArrayList<>();
83   private final ClientTransportServersBuilder clientTransportServersBuilder;
84   HandlerRegistry fallbackRegistry = DEFAULT_FALLBACK_REGISTRY;
85   ObjectPool<? extends Executor> executorPool = DEFAULT_EXECUTOR_POOL;
86   DecompressorRegistry decompressorRegistry = DEFAULT_DECOMPRESSOR_REGISTRY;
87   CompressorRegistry compressorRegistry = DEFAULT_COMPRESSOR_REGISTRY;
88   long handshakeTimeoutMillis = DEFAULT_HANDSHAKE_TIMEOUT_MILLIS;
89   Deadline.Ticker ticker = Deadline.getSystemTicker();
90   private boolean statsEnabled = true;
91   private boolean recordStartedRpcs = true;
92   private boolean recordFinishedRpcs = true;
93   private boolean recordRealTimeMetrics = false;
94   private boolean tracingEnabled = true;
95   @Nullable BinaryLog binlog;
96   InternalChannelz channelz = InternalChannelz.instance();
97   CallTracer.Factory callTracerFactory = CallTracer.getDefaultFactory();
98   @Nullable
99   ServerCallExecutorSupplier executorSupplier;
100 
101   /**
102    * An interface to provide to provide transport specific information for the server. This method
103    * is meant for Transport implementors and should not be used by normal users.
104    */
105   public interface ClientTransportServersBuilder {
buildClientTransportServers( List<? extends ServerStreamTracer.Factory> streamTracerFactories)106     InternalServer buildClientTransportServers(
107         List<? extends ServerStreamTracer.Factory> streamTracerFactories);
108   }
109 
110   /**
111    * Creates a new server builder with given transport servers provider.
112    */
ServerImplBuilder(ClientTransportServersBuilder clientTransportServersBuilder)113   public ServerImplBuilder(ClientTransportServersBuilder clientTransportServersBuilder) {
114     this.clientTransportServersBuilder = checkNotNull(clientTransportServersBuilder,
115         "clientTransportServersBuilder");
116   }
117 
118   @Override
directExecutor()119   public ServerImplBuilder directExecutor() {
120     return executor(MoreExecutors.directExecutor());
121   }
122 
123   @Override
executor(@ullable Executor executor)124   public ServerImplBuilder executor(@Nullable Executor executor) {
125     this.executorPool = executor != null ? new FixedObjectPool<>(executor) : DEFAULT_EXECUTOR_POOL;
126     return this;
127   }
128 
129   @Override
callExecutor(ServerCallExecutorSupplier executorSupplier)130   public ServerImplBuilder callExecutor(ServerCallExecutorSupplier executorSupplier) {
131     this.executorSupplier = checkNotNull(executorSupplier);
132     return this;
133   }
134 
135   @Override
addService(ServerServiceDefinition service)136   public ServerImplBuilder addService(ServerServiceDefinition service) {
137     registryBuilder.addService(checkNotNull(service, "service"));
138     return this;
139   }
140 
141   @Override
addService(BindableService bindableService)142   public ServerImplBuilder addService(BindableService bindableService) {
143     return addService(checkNotNull(bindableService, "bindableService").bindService());
144   }
145 
146   @Override
addTransportFilter(ServerTransportFilter filter)147   public ServerImplBuilder addTransportFilter(ServerTransportFilter filter) {
148     transportFilters.add(checkNotNull(filter, "filter"));
149     return this;
150   }
151 
152   @Override
intercept(ServerInterceptor interceptor)153   public ServerImplBuilder intercept(ServerInterceptor interceptor) {
154     interceptors.add(checkNotNull(interceptor, "interceptor"));
155     return this;
156   }
157 
158   @Override
addStreamTracerFactory(ServerStreamTracer.Factory factory)159   public ServerImplBuilder addStreamTracerFactory(ServerStreamTracer.Factory factory) {
160     streamTracerFactories.add(checkNotNull(factory, "factory"));
161     return this;
162   }
163 
164   @Override
fallbackHandlerRegistry(@ullable HandlerRegistry registry)165   public ServerImplBuilder fallbackHandlerRegistry(@Nullable HandlerRegistry registry) {
166     this.fallbackRegistry = registry != null ? registry : DEFAULT_FALLBACK_REGISTRY;
167     return this;
168   }
169 
170   @Override
decompressorRegistry(@ullable DecompressorRegistry registry)171   public ServerImplBuilder decompressorRegistry(@Nullable DecompressorRegistry registry) {
172     this.decompressorRegistry = registry != null ? registry : DEFAULT_DECOMPRESSOR_REGISTRY;
173     return this;
174   }
175 
176   @Override
compressorRegistry(@ullable CompressorRegistry registry)177   public ServerImplBuilder compressorRegistry(@Nullable CompressorRegistry registry) {
178     this.compressorRegistry = registry != null ? registry : DEFAULT_COMPRESSOR_REGISTRY;
179     return this;
180   }
181 
182   @Override
handshakeTimeout(long timeout, TimeUnit unit)183   public ServerImplBuilder handshakeTimeout(long timeout, TimeUnit unit) {
184     checkArgument(timeout > 0, "handshake timeout is %s, but must be positive", timeout);
185     this.handshakeTimeoutMillis = checkNotNull(unit, "unit").toMillis(timeout);
186     return this;
187   }
188 
189   @Override
setBinaryLog(@ullable BinaryLog binaryLog)190   public ServerImplBuilder setBinaryLog(@Nullable BinaryLog binaryLog) {
191     this.binlog = binaryLog;
192     return this;
193   }
194 
195   /**
196    * Disable or enable stats features.  Enabled by default.
197    */
setStatsEnabled(boolean value)198   public void setStatsEnabled(boolean value) {
199     this.statsEnabled = value;
200   }
201 
202   /**
203    * Disable or enable stats recording for RPC upstarts.  Effective only if {@link
204    * #setStatsEnabled} is set to true.  Enabled by default.
205    */
setStatsRecordStartedRpcs(boolean value)206   public void setStatsRecordStartedRpcs(boolean value) {
207     recordStartedRpcs = value;
208   }
209 
210   /**
211    * Disable or enable stats recording for RPC completions.  Effective only if {@link
212    * #setStatsEnabled} is set to true.  Enabled by default.
213    */
setStatsRecordFinishedRpcs(boolean value)214   public void setStatsRecordFinishedRpcs(boolean value) {
215     recordFinishedRpcs = value;
216   }
217 
218   /**
219    * Disable or enable real-time metrics recording.  Effective only if {@link #setStatsEnabled} is
220    * set to true.  Disabled by default.
221    */
setStatsRecordRealTimeMetrics(boolean value)222   public void setStatsRecordRealTimeMetrics(boolean value) {
223     recordRealTimeMetrics = value;
224   }
225 
226   /**
227    * Disable or enable tracing features.  Enabled by default.
228    */
setTracingEnabled(boolean value)229   public void setTracingEnabled(boolean value) {
230     tracingEnabled = value;
231   }
232 
233   /**
234    * Sets a custom deadline ticker.  This should only be called from InProcessServerBuilder.
235    */
setDeadlineTicker(Deadline.Ticker ticker)236   public void setDeadlineTicker(Deadline.Ticker ticker) {
237     this.ticker = checkNotNull(ticker, "ticker");
238   }
239 
240   @Override
build()241   public Server build() {
242     return new ServerImpl(this,
243         clientTransportServersBuilder.buildClientTransportServers(getTracerFactories()),
244         Context.ROOT);
245   }
246 
247   @VisibleForTesting
getTracerFactories()248   List<? extends ServerStreamTracer.Factory> getTracerFactories() {
249     ArrayList<ServerStreamTracer.Factory> tracerFactories = new ArrayList<>();
250     boolean isGlobalInterceptorsTracersSet = false;
251     List<ServerInterceptor> globalServerInterceptors
252         = InternalGlobalInterceptors.getServerInterceptors();
253     List<ServerStreamTracer.Factory> globalServerStreamTracerFactories
254         = InternalGlobalInterceptors.getServerStreamTracerFactories();
255     if (globalServerInterceptors != null) {
256       tracerFactories.addAll(globalServerStreamTracerFactories);
257       interceptors.addAll(globalServerInterceptors);
258       isGlobalInterceptorsTracersSet = true;
259     }
260     if (!isGlobalInterceptorsTracersSet && statsEnabled) {
261       ServerStreamTracer.Factory censusStatsTracerFactory = null;
262       try {
263         Class<?> censusStatsAccessor =
264             Class.forName("io.grpc.census.InternalCensusStatsAccessor");
265         Method getServerStreamTracerFactoryMethod =
266             censusStatsAccessor.getDeclaredMethod(
267                 "getServerStreamTracerFactory",
268                 boolean.class,
269                 boolean.class,
270                 boolean.class);
271         censusStatsTracerFactory =
272             (ServerStreamTracer.Factory) getServerStreamTracerFactoryMethod
273                 .invoke(
274                     null,
275                     recordStartedRpcs,
276                     recordFinishedRpcs,
277                     recordRealTimeMetrics);
278       } catch (ClassNotFoundException e) {
279         // Replace these separate catch statements with multicatch when Android min-API >= 19
280         log.log(Level.FINE, "Unable to apply census stats", e);
281       } catch (NoSuchMethodException e) {
282         log.log(Level.FINE, "Unable to apply census stats", e);
283       } catch (IllegalAccessException e) {
284         log.log(Level.FINE, "Unable to apply census stats", e);
285       } catch (InvocationTargetException e) {
286         log.log(Level.FINE, "Unable to apply census stats", e);
287       }
288       if (censusStatsTracerFactory != null) {
289         tracerFactories.add(censusStatsTracerFactory);
290       }
291     }
292     if (!isGlobalInterceptorsTracersSet && tracingEnabled) {
293       ServerStreamTracer.Factory tracingStreamTracerFactory = null;
294       try {
295         Class<?> censusTracingAccessor =
296             Class.forName("io.grpc.census.InternalCensusTracingAccessor");
297         Method getServerStreamTracerFactoryMethod =
298             censusTracingAccessor.getDeclaredMethod("getServerStreamTracerFactory");
299         tracingStreamTracerFactory =
300             (ServerStreamTracer.Factory) getServerStreamTracerFactoryMethod.invoke(null);
301       } catch (ClassNotFoundException e) {
302         // Replace these separate catch statements with multicatch when Android min-API >= 19
303         log.log(Level.FINE, "Unable to apply census stats", e);
304       } catch (NoSuchMethodException e) {
305         log.log(Level.FINE, "Unable to apply census stats", e);
306       } catch (IllegalAccessException e) {
307         log.log(Level.FINE, "Unable to apply census stats", e);
308       } catch (InvocationTargetException e) {
309         log.log(Level.FINE, "Unable to apply census stats", e);
310       }
311       if (tracingStreamTracerFactory != null) {
312         tracerFactories.add(tracingStreamTracerFactory);
313       }
314     }
315     tracerFactories.addAll(streamTracerFactories);
316     tracerFactories.trimToSize();
317     return Collections.unmodifiableList(tracerFactories);
318   }
319 
getChannelz()320   public InternalChannelz getChannelz() {
321     return channelz;
322   }
323 
324   private static final class DefaultFallbackRegistry extends HandlerRegistry {
325     @Override
getServices()326     public List<ServerServiceDefinition> getServices() {
327       return Collections.emptyList();
328     }
329 
330     @Nullable
331     @Override
lookupMethod( String methodName, @Nullable String authority)332     public ServerMethodDefinition<?, ?> lookupMethod(
333         String methodName, @Nullable String authority) {
334       return null;
335     }
336   }
337 
338   /**
339    * Returns the internal ExecutorPool for offloading tasks.
340    */
getExecutorPool()341   public ObjectPool<? extends Executor> getExecutorPool() {
342     return this.executorPool;
343   }
344 
345   @Override
useTransportSecurity(File certChain, File privateKey)346   public ServerImplBuilder useTransportSecurity(File certChain, File privateKey) {
347     throw new UnsupportedOperationException("TLS not supported in ServerImplBuilder");
348   }
349 }
350