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.checkNotNull; 20 21 import com.google.common.base.Preconditions; 22 import com.google.errorprone.annotations.DoNotCall; 23 import io.grpc.Deadline; 24 import io.grpc.ExperimentalApi; 25 import io.grpc.Internal; 26 import io.grpc.ServerBuilder; 27 import io.grpc.ServerStreamTracer; 28 import io.grpc.internal.AbstractServerImplBuilder; 29 import io.grpc.internal.FixedObjectPool; 30 import io.grpc.internal.GrpcUtil; 31 import io.grpc.internal.InternalServer; 32 import io.grpc.internal.ObjectPool; 33 import io.grpc.internal.ServerImplBuilder; 34 import io.grpc.internal.ServerImplBuilder.ClientTransportServersBuilder; 35 import io.grpc.internal.SharedResourcePool; 36 import java.io.File; 37 import java.net.SocketAddress; 38 import java.util.List; 39 import java.util.UUID; 40 import java.util.concurrent.ScheduledExecutorService; 41 import java.util.concurrent.TimeUnit; 42 43 /** 44 * Builder for a server that services in-process requests. Clients identify the in-process server by 45 * its name. 46 * 47 * <p>The server is intended to be fully-featured, high performance, and useful in testing. 48 * 49 * <h3>Using JUnit TestRule</h3> 50 * The class "GrpcServerRule" (from "grpc-java/testing") is a JUnit TestRule that 51 * creates a {@link InProcessServer} and a {@link io.grpc.ManagedChannel ManagedChannel}. This 52 * test rule contains the boilerplate code shown below. The classes "HelloWorldServerTest" and 53 * "HelloWorldClientTest" (from "grpc-java/examples") demonstrate basic usage. 54 * 55 * <h3>Usage example</h3> 56 * <h4>Server and client channel setup</h4> 57 * <pre> 58 * String uniqueName = InProcessServerBuilder.generateName(); 59 * Server server = InProcessServerBuilder.forName(uniqueName) 60 * .directExecutor() // directExecutor is fine for unit tests 61 * .addService(/* your code here */) 62 * .build().start(); 63 * ManagedChannel channel = InProcessChannelBuilder.forName(uniqueName) 64 * .directExecutor() 65 * .build(); 66 * </pre> 67 * 68 * <h4>Usage in tests</h4> 69 * The channel can be used normally. A blocking stub example: 70 * <pre> 71 * TestServiceGrpc.TestServiceBlockingStub blockingStub = 72 * TestServiceGrpc.newBlockingStub(channel); 73 * </pre> 74 */ 75 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1783") 76 public final class InProcessServerBuilder extends 77 AbstractServerImplBuilder<InProcessServerBuilder> { 78 /** 79 * Create a server builder that will bind with the given name. 80 * 81 * @param name the identity of the server for clients to connect to 82 * @return a new builder 83 */ forName(String name)84 public static InProcessServerBuilder forName(String name) { 85 return forAddress(new InProcessSocketAddress(checkNotNull(name, "name"))); 86 } 87 88 /** 89 * Create a server builder which listens on the given address. 90 * @param listenAddress The SocketAddress this server will listen on. 91 * @return a new builder 92 */ forAddress(SocketAddress listenAddress)93 public static InProcessServerBuilder forAddress(SocketAddress listenAddress) { 94 return new InProcessServerBuilder(listenAddress); 95 } 96 97 /** 98 * Always fails. Call {@link #forName} instead. 99 */ 100 @DoNotCall("Unsupported. Use forName() instead") forPort(int port)101 public static InProcessServerBuilder forPort(int port) { 102 throw new UnsupportedOperationException("call forName() instead"); 103 } 104 105 /** 106 * Generates a new server name that is unique each time. 107 */ generateName()108 public static String generateName() { 109 return UUID.randomUUID().toString(); 110 } 111 112 private final ServerImplBuilder serverImplBuilder; 113 final SocketAddress listenAddress; 114 int maxInboundMetadataSize = Integer.MAX_VALUE; 115 ObjectPool<ScheduledExecutorService> schedulerPool = 116 SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE); 117 InProcessServerBuilder(SocketAddress listenAddress)118 private InProcessServerBuilder(SocketAddress listenAddress) { 119 this.listenAddress = checkNotNull(listenAddress, "listenAddress"); 120 121 final class InProcessClientTransportServersBuilder implements ClientTransportServersBuilder { 122 @Override 123 public InternalServer buildClientTransportServers( 124 List<? extends ServerStreamTracer.Factory> streamTracerFactories) { 125 return buildTransportServers(streamTracerFactories); 126 } 127 } 128 129 serverImplBuilder = new ServerImplBuilder(new InProcessClientTransportServersBuilder()); 130 131 // In-process transport should not record its traffic to the stats module. 132 // https://github.com/grpc/grpc-java/issues/2284 133 serverImplBuilder.setStatsRecordStartedRpcs(false); 134 serverImplBuilder.setStatsRecordFinishedRpcs(false); 135 // Disable handshake timeout because it is unnecessary, and can trigger Thread creation that can 136 // break some environments (like tests). 137 handshakeTimeout(Long.MAX_VALUE, TimeUnit.SECONDS); 138 } 139 140 @Internal 141 @Override delegate()142 protected ServerBuilder<?> delegate() { 143 return serverImplBuilder; 144 } 145 146 /** 147 * Provides a custom scheduled executor service. 148 * 149 * <p>It's an optional parameter. If the user has not provided a scheduled executor service when 150 * the channel is built, the builder will use a static cached thread pool. 151 * 152 * @return this 153 * 154 * @since 1.11.0 155 */ scheduledExecutorService( ScheduledExecutorService scheduledExecutorService)156 public InProcessServerBuilder scheduledExecutorService( 157 ScheduledExecutorService scheduledExecutorService) { 158 schedulerPool = new FixedObjectPool<>( 159 checkNotNull(scheduledExecutorService, "scheduledExecutorService")); 160 return this; 161 } 162 163 /** 164 * Provides a custom deadline ticker that this server will use to create incoming {@link 165 * Deadline}s. 166 * 167 * <p>This is intended for unit tests that fake out the clock. You should also have a fake {@link 168 * ScheduledExecutorService} whose clock is synchronized with this ticker and set it to {@link 169 * #scheduledExecutorService}. DO NOT use this in production. 170 * 171 * @return this 172 * @see Deadline#after(long, TimeUnit, Deadline.Ticker) 173 * 174 * @since 1.24.0 175 */ deadlineTicker(Deadline.Ticker ticker)176 public InProcessServerBuilder deadlineTicker(Deadline.Ticker ticker) { 177 serverImplBuilder.setDeadlineTicker(ticker); 178 return this; 179 } 180 181 /** 182 * Sets the maximum size of metadata allowed to be received. {@code Integer.MAX_VALUE} disables 183 * the enforcement. Defaults to no limit ({@code Integer.MAX_VALUE}). 184 * 185 * <p>There is potential for performance penalty when this setting is enabled, as the Metadata 186 * must actually be serialized. Since the current implementation of Metadata pre-serializes, it's 187 * currently negligible. But Metadata is free to change its implementation. 188 * 189 * @param bytes the maximum size of received metadata 190 * @return this 191 * @throws IllegalArgumentException if bytes is non-positive 192 * @since 1.17.0 193 */ 194 @Override maxInboundMetadataSize(int bytes)195 public InProcessServerBuilder maxInboundMetadataSize(int bytes) { 196 Preconditions.checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0"); 197 this.maxInboundMetadataSize = bytes; 198 return this; 199 } 200 buildTransportServers( List<? extends ServerStreamTracer.Factory> streamTracerFactories)201 InProcessServer buildTransportServers( 202 List<? extends ServerStreamTracer.Factory> streamTracerFactories) { 203 return new InProcessServer(this, streamTracerFactories); 204 } 205 206 @Override useTransportSecurity(File certChain, File privateKey)207 public InProcessServerBuilder useTransportSecurity(File certChain, File privateKey) { 208 throw new UnsupportedOperationException("TLS not supported in InProcessServer"); 209 } 210 setStatsEnabled(boolean value)211 void setStatsEnabled(boolean value) { 212 this.serverImplBuilder.setStatsEnabled(value); 213 } 214 } 215