Skip to content

Commit f33d010

Browse files
authored
Merge pull request #1454 from SpineEventEngine/1.x-configure-grpc-server
[1.x] Allow to configure the underlying gRPC server
2 parents bb32296 + f276fda commit f33d010

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

server/src/main/java/io/spine/server/GrpcContainer.java

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@
3636
import io.grpc.ServerBuilder;
3737
import io.grpc.ServerServiceDefinition;
3838
import io.grpc.inprocess.InProcessServerBuilder;
39+
import io.spine.annotation.Experimental;
3940
import io.spine.client.ConnectionConstants;
4041
import org.checkerframework.checker.nullness.qual.Nullable;
4142

4243
import java.io.IOException;
4344
import java.util.Optional;
4445
import java.util.Set;
4546
import java.util.concurrent.Executor;
47+
import java.util.function.Function;
4648

4749
import static com.google.common.base.Preconditions.checkNotNull;
4850
import static com.google.common.base.Preconditions.checkState;
51+
import static io.spine.server.GrpcContainer.ConfigureServer.doNothing;
4952
import static java.lang.String.format;
5053
import static java.util.Objects.requireNonNull;
5154

@@ -70,6 +73,7 @@ public final class GrpcContainer {
7073
private final @Nullable Integer port;
7174
private final @Nullable String serverName;
7275
private final ImmutableSet<ServerServiceDefinition> services;
76+
private final ConfigureServer configureServer;
7377

7478
private @Nullable Server grpcServer;
7579

@@ -106,6 +110,9 @@ private GrpcContainer(Builder builder) {
106110
this.port = builder.port().orElse(null);
107111
this.serverName = builder.serverName().orElse(null);
108112
this.services = builder.services();
113+
this.configureServer = builder.configureServer == null
114+
? doNothing()
115+
: builder.configureServer;
109116
}
110117

111118
/**
@@ -284,6 +291,7 @@ private Server createGrpcServer(@Nullable Executor executor) {
284291
for (ServerServiceDefinition service : services) {
285292
builder.addService(service);
286293
}
294+
builder = configureServer.apply(builder);
287295
return builder.build();
288296
}
289297

@@ -324,7 +332,8 @@ private static ServerBuilder<?> builderAtPort(Integer port, @Nullable Executor e
324332
* Injects a server to this container.
325333
*
326334
* <p>All calls to {@link #createGrpcServer(Executor)} will resolve to the given server
327-
* instance.
335+
* instance. The server instance is used as-is, no other
336+
* {@linkplain Builder#withServer(ConfigureServer) configuration methods} have any effect on it.
328337
*
329338
* <p>A test-only method.
330339
*/
@@ -380,6 +389,7 @@ private void println(@FormatString String msgFormat, Object... arg) {
380389
public static final class Builder extends ConnectionBuilder {
381390

382391
private final Set<ServerServiceDefinition> services = Sets.newHashSet();
392+
private @Nullable ConfigureServer configureServer;
383393

384394
private Builder(@Nullable Integer port, @Nullable String serverName) {
385395
super(port, serverName);
@@ -405,18 +415,52 @@ public int getPort() {
405415
return port().orElse(0);
406416
}
407417

418+
/**
419+
* Adds a gRPC service to deploy within the container being built.
420+
*
421+
* @return this instance of {@code Builder}, for call chaining
422+
*/
408423
@CanIgnoreReturnValue
409424
public Builder addService(BindableService service) {
425+
checkNotNull(service);
410426
services.add(service.bindService());
411427
return this;
412428
}
413429

430+
/**
431+
* Removes the {@linkplain #addService(BindableService) previously added}
432+
* gRPC service.
433+
*
434+
* <p>If the service under the given definition was not added previously,
435+
* this method does nothing.
436+
*
437+
* @return this instance of {@code Builder}, for call chaining
438+
*/
414439
@CanIgnoreReturnValue
415440
public Builder removeService(ServerServiceDefinition service) {
416441
services.remove(service);
417442
return this;
418443
}
419444

445+
/**
446+
* Sets an additional configuration action for the gRPC {@link Server} instance,
447+
* created for this {@code GrpcContainer} to run on top of. This configuration is applied
448+
* right before the {@linkplain #start() server is started}.
449+
*
450+
* <p>Allows the direct access to gRPC {@link ServerBuilder}'s API.
451+
*
452+
* <p>Please note this API is experimental.
453+
*
454+
* @return this instance of {@code Builder}, for call chaining
455+
* @see ConfigureServer
456+
*/
457+
@Experimental
458+
@CanIgnoreReturnValue
459+
public Builder withServer(ConfigureServer action) {
460+
this.configureServer = checkNotNull(action);
461+
return this;
462+
}
463+
420464
/**
421465
* Obtains the services already added to the builder.
422466
*
@@ -438,4 +482,40 @@ public GrpcContainer build() {
438482
return new GrpcContainer(this);
439483
}
440484
}
485+
486+
/**
487+
* Allows to configure the gRPC's {@link Server} instance,
488+
* on top of which this {@code GrpcContainer} will operate.
489+
*
490+
* <p>It is expected that the obtained builder of gRPC server is used to perform
491+
* some fine-grained tuning of its features. The same instance of {@link ServerBuilder}
492+
* should be returned.
493+
*
494+
* <p>Example.
495+
*
496+
* <pre>
497+
*
498+
* GrpcContainer container =
499+
* GrpcContainer.atPort(1654)
500+
* {@literal .withServer((server) -> server.maxInboundMessageSize(16_000_000)) }
501+
* // ...
502+
* .build();
503+
*
504+
* </pre>
505+
*
506+
* <p>Please note this interface is a part of experimental API.
507+
*
508+
* @see Builder#withServer(ConfigureServer)
509+
*/
510+
@Experimental
511+
@FunctionalInterface
512+
public interface ConfigureServer extends Function<ServerBuilder<?>, ServerBuilder<?>> {
513+
514+
/**
515+
* Returns an instance which does nothing and returns the same {@code ServerBuilder}.
516+
*/
517+
static ConfigureServer doNothing() {
518+
return builder -> builder;
519+
}
520+
}
441521
}

server/src/test/java/io/spine/server/GrpcContainerTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.junit.jupiter.api.Test;
3838

3939
import java.io.IOException;
40+
import java.util.List;
4041
import java.util.Set;
4142

4243
import static com.google.common.truth.Truth.assertThat;
@@ -109,6 +110,38 @@ void startServerWithExecutor() throws IOException {
109110
.isNotNull();
110111
}
111112

113+
@Test
114+
@DisplayName("configure underlying gRPC server")
115+
void configureUnderlyingGrpcServer() {
116+
int port = 1654;
117+
CommandService service = CommandService.newBuilder()
118+
.build();
119+
GrpcContainer container =
120+
GrpcContainer.atPort(port)
121+
.withServer((server) -> server.addService(service))
122+
.build();
123+
try {
124+
container.start();
125+
Server server = container.grpcServer();
126+
assertThat(server)
127+
.isNotNull();
128+
129+
List<ServerServiceDefinition> deployedServices = server.getServices();
130+
assertThat(deployedServices)
131+
.hasSize(1);
132+
133+
String actualName = deployedServices.get(0)
134+
.getServiceDescriptor()
135+
.getName();
136+
assertThat(actualName).contains(service.getClass()
137+
.getSimpleName());
138+
} catch (IOException e) {
139+
fail(e);
140+
} finally {
141+
container.shutdown();
142+
}
143+
}
144+
112145
@Test
113146
@DisplayName("shutdown server")
114147
void shutdownItself() throws IOException {

version.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
/**
3535
* Version of this library.
3636
*/
37-
val coreJava = "1.8.2-SNAPSHOT.1"
37+
val coreJava = "1.8.2"
3838

3939
/**
4040
* Versions of the Spine libraries that `core-java` depends on.

0 commit comments

Comments
 (0)