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