下面列出了org.springframework.boot.web.server.WebServer#com.linecorp.armeria.server.Server 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void serverStopping(Server server) throws Exception {
closed = true;
final ScheduledFuture<?> heartBeatFuture = this.heartBeatFuture;
if (heartBeatFuture != null) {
heartBeatFuture.cancel(false);
}
final String appName = this.appName;
if (appName != null) {
final String instanceId = instanceInfo.getInstanceId();
assert instanceId != null;
client.cancel(appName, instanceId).aggregate().handle((res, cause) -> {
if (cause != null) {
logger.warn("Failed to deregister from Eureka: {}", client.uri(), cause);
} else if (!res.status().isSuccess()) {
logger.warn("Failed to deregister from Eureka: {} (status: {}, content: {})",
client.uri(), res.status(), res.contentUtf8());
}
return null;
});
}
}
public static void main(String[] args) {
HelloService.AsyncIface helloHandler = new HelloService.AsyncIface(){
@Override
public void hello(AsyncMethodCallback resultHandler) throws TException {
resultHandler.onComplete("Hello world");
}
};
ServerBuilder sb = new ServerBuilder();
sb.port(8080, SessionProtocol.HTTP);
sb.serviceAt("/hello", ThriftService.of(helloHandler, SerializationFormat.THRIFT_BINARY))
.serviceUnder("/docs/", new DocService());
Server server= sb.build();
server.start();
}
private LocalArmeriaPortElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
final LocalArmeriaPort localArmeriaPort = ae.getAnnotation(LocalArmeriaPort.class);
final SessionProtocol protocol = localArmeriaPort.value();
Server server = getServer();
if (server == null) {
server = beanFactory.getBean(Server.class);
serServer(server);
}
Integer port = portCache.get(protocol);
if (port == null) {
port = server.activeLocalPort(protocol);
portCache.put(protocol, port);
}
this.port = port;
}
/**
* Ensure Armeria's dependencies do not cause a trouble with hbase-shaded-client.
*
* @see <a href="https://issues.apache.org/jira/browse/HBASE-14963">HBASE-14963</a>
*/
@Test(expected = NotAllMetaRegionsOnlineException.class)
public void testGuavaConflict() throws Exception {
// Make sure Armeria is available in the class path.
assertThat(Version.getAll(Server.class.getClassLoader())).isNotNull();
// Make sure newer Guava is available in the class path.
assertThat(Stopwatch.class.getDeclaredConstructor().getModifiers()).is(new Condition<>(
value -> !Modifier.isPublic(value),
"Recent Guava Stopwatch should have non-public default constructor."));
final MetaTableLocator locator = new MetaTableLocator();
final ZooKeeperWatcher zkw = mock(ZooKeeperWatcher.class);
final RecoverableZooKeeper zk = mock(RecoverableZooKeeper.class);
when(zkw.getRecoverableZooKeeper()).thenReturn(zk);
when(zk.exists(any(), any())).thenReturn(new Stat(0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0));
locator.waitMetaRegionLocation(zkw, 100);
}
private static ZooKeeperRegistrationSpec serverSetsSpec(
ServerSetsRegistrationSpec spec, Server server) {
final ServerSetsInstance serverSetsInstance = spec.serverSetsInstance();
if (serverSetsInstance.serviceEndpoint() != null) {
warnIfInactivePort(server, serverSetsInstance.serviceEndpoint().port(), null);
return spec;
}
final ServerSetsRegistrationSpecBuilder builder =
ZooKeeperRegistrationSpec.builderForServerSets();
builder.serviceEndpoint(defaultEndpoint(server))
.additionalEndpoints(serverSetsInstance.additionalEndpoints())
.metadata(serverSetsInstance.metadata())
.sequential(spec.isSequential())
.nodeName(spec.path().substring(1)); // Simply remove prepended '/'.
final Integer shardId = serverSetsInstance.shardId();
if (shardId != null) {
builder.shardId(shardId);
}
return builder.build();
}
@Test
void serviceAddedIsCalled() {
final AtomicReference<ServiceConfig> cfgHolder = new AtomicReference<>();
final THttpService tHttpService =
ThriftCallService.of((AsyncIface) (name, cb) -> cb.onComplete("name"))
.decorate(delegate -> new SimpleDecoratingRpcService(delegate) {
@Override
public void serviceAdded(ServiceConfig cfg) throws Exception {
cfgHolder.set(cfg);
}
@Override
public RpcResponse serve(
ServiceRequestContext ctx, RpcRequest req) throws Exception {
return new CompletableRpcResponse();
}
}).decorate(THttpService.newDecorator());
Server.builder().service("/", tHttpService).build();
final ServiceConfig serviceConfig = cfgHolder.get();
assertThat(serviceConfig).isNotNull();
assertThat(serviceConfig.service()).isInstanceOf(THttpService.class);
final ThriftCallService thriftCallService = tHttpService.as(ThriftCallService.class);
assertThat(thriftCallService).isNotNull();
}
@Test
void legacyZooKeeperRegistrationSpec() throws Throwable {
final List<Server> servers = startServers(true);
// all servers start and with znode created
await().untilAsserted(() -> sampleEndpoints.forEach(
endpoint -> zkInstance.assertExists(Z_NODE + '/' + endpoint.host() + '_' + endpoint.port())));
try (CloseableZooKeeper zk = zkInstance.connection()) {
for (Endpoint sampleEndpoint : sampleEndpoints) {
assertThat(ZooKeeperDiscoverySpec.legacy().decode(zk.getData(
Z_NODE + '/' + sampleEndpoint.host() + '_' + sampleEndpoint.port()).get()))
.isEqualTo(sampleEndpoint);
}
validateOneNodeRemoved(servers, zk, true);
}
servers.forEach(s -> s.stop().join());
}
private static void validateOneNodeRemoved(
List<Server> servers, CloseableZooKeeper zk, boolean endpointRegistrationSpec) throws Throwable {
servers.get(0).stop().get();
servers.remove(0);
int removed = 0;
int remaining = 0;
for (int i = 0; i < sampleEndpoints.size(); i++) {
final String key;
if (endpointRegistrationSpec) {
key = Z_NODE + '/' + sampleEndpoints.get(i).host() + '_' + sampleEndpoints.get(i).port();
} else {
key = Z_NODE + '/' + CURATOR_X_SERVICE_NAME + '/' + i;
}
if (zk.exists(key).get()) {
remaining++;
} else {
removed++;
}
}
assertThat(removed).isOne();
assertThat(remaining).isEqualTo(sampleEndpoints.size() - 1);
}
private static List<Server> startServers(boolean endpointRegistrationSpec) {
final List<Server> servers = new ArrayList<>();
for (int i = 0; i < sampleEndpoints.size(); i++) {
final Server server = Server.builder()
.http(sampleEndpoints.get(i).port())
.service("/", (ctx, req) -> HttpResponse.of(200))
.build();
final ZooKeeperRegistrationSpec registrationSpec;
if (endpointRegistrationSpec) {
registrationSpec = ZooKeeperRegistrationSpec.legacy(sampleEndpoints.get(i));
} else {
registrationSpec = ZooKeeperRegistrationSpec.builderForCurator(CURATOR_X_SERVICE_NAME)
.serviceId(String.valueOf(i))
.serviceAddress(CURATOR_X_ADDRESS)
.build();
}
final ServerListener listener =
ZooKeeperUpdatingListener.builder(zkInstance.connectString(), Z_NODE, registrationSpec)
.sessionTimeoutMillis(SESSION_TIMEOUT_MILLIS)
.build();
server.addListener(listener);
server.start().join();
servers.add(server);
}
return servers;
}
@Test
void noSequential() throws Throwable {
final List<Endpoint> endpoints = ZooKeeperTestUtil.sampleEndpoints(1);
final ServerSetsRegistrationSpecBuilder specBuilder =
ZooKeeperRegistrationSpec.builderForServerSets();
final ZooKeeperRegistrationSpec spec =
specBuilder.serviceEndpoint(Endpoint.of("127.0.0.1", endpoints.get(0).port()))
.nodeName("foo")
.sequential(false)
.build();
final ZooKeeperUpdatingListener listener =
ZooKeeperUpdatingListener.builder(zkInstance.connectString(), Z_NODE, spec).build();
final Server server = Server.builder()
.serverListener(listener)
.http(endpoints.get(0).port())
.service("/", (ctx, req) -> HttpResponse.of(200))
.build();
server.start().join();
try (CloseableZooKeeper zk = zkInstance.connection()) {
// nodeName is not sequential.
await().untilAsserted(() -> zkInstance.assertExists(Z_NODE + "/foo"));
}
server.stop().join();
await().untilAsserted(() -> zkInstance.assertNotExists(Z_NODE + "/foo"));
}
public static void main(String[] args) {
final Server backend = Server.builder()
.service("/square/{num}", ((ctx, req) -> {
final long num = Long.parseLong(ctx.pathParam("num"));
return HttpResponse.of(Long.toString(num * num));
}))
.http(8081)
.build();
final WebClient backendClient = WebClient.of("http://localhost:8081");
final Server frontend =
Server.builder()
.http(8080)
.serviceUnder("/", new MainService(backendClient))
.build();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
backend.stop().join();
frontend.stop().join();
}));
backend.start().join();
frontend.start().join();
}
public static void main(String[] args) {
final Server backend = Server.builder()
.service("/square/{num}", ((ctx, req) -> {
final long num = Long.parseLong(ctx.pathParam("num"));
return HttpResponse.of(Long.toString(num * num));
}))
.http(8081)
.build();
final Server frontend = DaggerMain_MainComponent.create().server();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
backend.stop().join();
frontend.stop().join();
}));
backend.start().join();
frontend.start().join();
}
public static void main(String[] args) {
final Server backend = Server.builder()
.service("/square/{num}", (ctx, req) -> {
final long num = Long.parseLong(ctx.pathParam("num"));
return HttpResponse.of(Long.toString(num * num));
})
.http(8081)
.build();
final WebClient backendClient = WebClient.of("http://localhost:8081");
final Server frontend =
Server.builder()
.http(8080)
.serviceUnder("/", new MainService(backendClient))
.build();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
backend.stop().join();
frontend.stop().join();
}));
backend.start().join();
frontend.start().join();
}
static Server newServer(int httpPort, int httpsPort) throws Exception {
return Server.builder()
.http(httpPort)
.https(httpsPort)
.tlsSelfSigned()
// Serve an individual file.
.service("/favicon.ico",
HttpFile.of(Main.class.getClassLoader(), "favicon.ico")
.asService())
// Serve the files under the current user's home directory.
.service("prefix:/",
FileService.builder(Paths.get(System.getProperty("user.home")))
.autoIndex(true)
.build())
.build();
}
public static void main(String[] args) throws Exception {
final SamlServiceProvider ssp = samlServiceProvider();
final Server server =
Server.builder()
.https(8443)
// You can add this certificate to your trust store
// in order to make your web browser happy.
.tls(new File(ClassLoader.getSystemResource("localhost.crt").toURI()),
new File(ClassLoader.getSystemResource("localhost.key").toURI()))
// Decorate you service with SAML decorator.
.annotatedService("/", new MyService(), ssp.newSamlDecorator())
// Add SAML service to your server which handles a SAML response and a metadata request.
.service(ssp.newSamlService())
.build();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
server.stop().join();
logger.info("Server has been stopped.");
}));
server.start().join();
logger.info("Server has been started.");
}
void stop() throws Exception {
final org.apache.catalina.Server server = this.server;
final Connector connector = this.connector;
this.server = null;
this.connector = null;
if (engineName != null) {
activeEngines.remove(engineName);
engineName = null;
}
if (server == null || !started) {
return;
}
try {
logger.info("Stopping an embedded Tomcat: {}", toString(server));
server.stop();
} catch (Exception e) {
logger.warn("Failed to stop an embedded Tomcat: {}", toString(server), e);
}
postStopTask.accept(connector);
}
@Setup
public void startServer() throws Exception {
final ServerBuilder sb =
Server.builder()
.service("/a", THttpService.of((AsyncIface) (name, cb) -> cb.onComplete(RESPONSE))
.decorate(PooledDecoratingService::new))
.service("/b", THttpService.of((AsyncIface) (name, cb) -> cb.onComplete(RESPONSE))
.decorate(UnpooledDecoratingService::new));
server = sb.build();
server.start().join();
final int httpPort = server.activeLocalPort(SessionProtocol.HTTP);
pooledClient = Clients.newClient("tbinary+http://127.0.0.1:" + httpPort + "/a",
HelloService.Iface.class);
unpooledClient = Clients.newClient("tbinary+http://127.0.0.1:" + httpPort + "/b",
HelloService.Iface.class);
}
@Setup
public void startServer() {
final int port = 8080;
serverWithAdditionalHeaders = Server.builder()
.http(port)
.service("/header_conversion", (ctx, req) -> {
addAdditionalHeaders(ctx);
addProhibitedHeaders(ctx);
return HttpResponse.of(HttpStatus.OK);
})
.build();
serverWithAdditionalHeaders.start().join();
clientWithoutAdditionalHeadersHttp1 = WebClient.of("h1c://127.0.0.1:" + port);
clientWithoutAdditionalHeadersHttp2 = WebClient.of("h2c://127.0.0.1:" + port);
}
@BeforeEach void setUp() throws Exception {
consumerConfig = new Properties();
consumerConfig.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_BOOTSTRAP_SERVERS);
consumerConfig.put(ConsumerConfig.GROUP_ID_CONFIG, "test");
consumerConfig.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
consumerConfig.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
assertThat(kafkaContainer.isRunning()).isTrue();
traceTimeout = Duration.ofSeconds(5);
int serverPort = randomPort();
storageBuilder = KafkaStorage.newBuilder()
.bootstrapServers(KAFKA_BOOTSTRAP_SERVERS)
.storageStateDir("target/zipkin_" + System.currentTimeMillis())
.hostname("localhost")
.serverPort(serverPort);
storageBuilder.spanAggregation.traceTimeout(traceTimeout);
storage = (KafkaStorage) storageBuilder.build();
server = Server.builder()
.annotatedService("/storage/kafka", new KafkaStorageHttpService(storage))
.http(serverPort)
.build();
server.start();
Collection<NewTopic> newTopics = new ArrayList<>();
newTopics.add(new NewTopic(storageBuilder.spanAggregation.spansTopic, 1, (short) 1));
newTopics.add(new NewTopic(storageBuilder.spanAggregation.traceTopic, 1, (short) 1));
newTopics.add(new NewTopic(storageBuilder.spanAggregation.dependencyTopic, 1, (short) 1));
storage.getAdminClient().createTopics(newTopics).all().get();
await().atMost(10, TimeUnit.SECONDS).until(() -> storage.check().ok());
storage.checkResources();
Properties producerConfig = new Properties();
producerConfig.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_BOOTSTRAP_SERVERS);
tracesProducer = new KafkaProducer<>(producerConfig, new StringSerializer(),
spansSerde.serializer());
dependencyProducer = new KafkaProducer<>(producerConfig, new StringSerializer(),
dependencyLinkSerde.serializer());
}
/**
* Returns the ports of the server.
*
* @return the {@link Map} which contains the pairs of local {@link InetSocketAddress} and
* {@link ServerPort} is the server is started. {@link Optional#empty()} otherwise.
*/
public Map<InetSocketAddress, ServerPort> activePorts() {
final Server server = this.server;
if (server != null) {
return server.activePorts();
} else {
return Collections.emptyMap();
}
}
public StackdriverMockServer() {
this.server = Server.builder()
.service(GrpcService.builder()
.addService(new Service())
.build())
.tlsSelfSigned()
.build();
}
@Override protected Sender createSender() {
Route v2JsonSpans = Route.builder().methods(POST).consumes(JSON).path("/api/v2/spans").build();
server = Server.builder()
.http(0)
.gracefulShutdownTimeout(Duration.ZERO, Duration.ZERO)
.service(v2JsonSpans, (ctx, res) -> HttpResponse.of(202)).build();
server.start().join();
return newHttpSender(url("/api/v2/spans"));
}
public static void main(String[] args) throws Exception {
final Server server = newServer(8080, 8443);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
server.stop().join();
logger.info("Server has been stopped.");
}));
server.start().join();
final InetSocketAddress localAddress = server.activePort().localAddress();
final boolean isLocalAddress = localAddress.getAddress().isAnyLocalAddress() ||
localAddress.getAddress().isLoopbackAddress();
logger.info("Server has been started. Serving DocService at http://{}:{}/docs",
isLocalAddress ? "127.0.0.1" : localAddress.getHostString(), localAddress.getPort());
}
static Server newServer(int httpPort, int httpsPort) throws Exception {
final HelloRequest exampleRequest = HelloRequest.newBuilder().setName("Armeria").build();
final HttpServiceWithRoutes grpcService =
GrpcService.builder()
.addService(new HelloServiceImpl())
// See https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md
.addService(ProtoReflectionService.newInstance())
.supportedSerializationFormats(GrpcSerializationFormats.values())
.enableUnframedRequests(true)
// You can set useBlockingTaskExecutor(true) in order to execute all gRPC
// methods in the blockingTaskExecutor thread pool.
// .useBlockingTaskExecutor(true)
.build();
return Server.builder()
.http(httpPort)
.https(httpsPort)
.tlsSelfSigned()
.service(grpcService)
// You can access the documentation service at http://127.0.0.1:8080/docs.
// See https://line.github.io/armeria/server-docservice.html for more information.
.serviceUnder("/docs", DocService.builder()
.exampleRequestForMethod(HelloServiceGrpc.SERVICE_NAME,
"Hello", exampleRequest)
.exampleRequestForMethod(HelloServiceGrpc.SERVICE_NAME,
"LazyHello", exampleRequest)
.exampleRequestForMethod(HelloServiceGrpc.SERVICE_NAME,
"BlockingHello", exampleRequest)
.exclude(DocServiceFilter.ofServiceName(
ServerReflectionGrpc.SERVICE_NAME))
.build())
.build();
}
@Test
void configureServer() throws Exception {
final File yml = new File(resourceFilePath("armeria-settings.yaml"));
final ArmeriaSettings armeriaSettings = configFactory.build(yml);
armeriaSettings.setSsl(null);
final ServerBuilder serverBuilder = Server.builder()
.service("/foo", (ctx, req) -> HttpResponse.of(200));
serverBuilder.tlsSelfSigned();
ArmeriaConfigurationUtil.configureServer(serverBuilder, armeriaSettings);
final Server server = serverBuilder.build();
assertThat(server.defaultHostname()).isEqualTo("host.name.com");
assertThat(server.config().maxNumConnections()).isEqualTo(5000);
assertThat(server.config().isDateHeaderEnabled()).isFalse();
assertThat(server.config().isServerHeaderEnabled()).isTrue();
assertThat(server.config().defaultVirtualHost().maxRequestLength()).isEqualTo(10485761);
assertThat(server.config().ports()).hasSize(3);
assertThat(server.config().ports()).containsExactly(
new ServerPort(8080, SessionProtocol.HTTP),
new ServerPort(new InetSocketAddress("127.0.0.1", 8081), SessionProtocol.HTTPS),
new ServerPort(8443, SessionProtocol.HTTPS, SessionProtocol.PROXY)
);
assertThat(server.config().http1MaxChunkSize()).isEqualTo(4000);
assertThat(server.config().http1MaxInitialLineLength()).isEqualTo(4096);
assertThat(server.config().http1MaxInitialLineLength()).isEqualTo(4096);
assertThat(server.config().http2InitialConnectionWindowSize()).isEqualTo(1024 * 1024 * 2);
assertThat(server.config().http2InitialStreamWindowSize()).isEqualTo(1024 * 1024 * 2);
assertThat(server.config().http2MaxFrameSize()).isEqualTo(16385);
assertThat(server.config().http2MaxHeaderListSize()).isEqualTo(8193);
assertThat(server.config().proxyProtocolMaxTlvSize()).isEqualTo(65320);
}
@Override
public void serverStarted(Server server) throws Exception {
final InstanceInfo newInfo = fillAndCreateNewInfo(instanceInfo, server);
try (ClientRequestContextCaptor contextCaptor = Clients.newContextCaptor()) {
final HttpResponse response = client.register(newInfo);
final ClientRequestContext ctx = contextCaptor.get();
response.aggregate().handle((res, cause) -> {
if (closed) {
return null;
}
if (cause != null) {
logger.warn("Failed to register {} to Eureka: {}",
newInfo.getHostName(), client.uri(), cause);
return null;
}
final ResponseHeaders headers = res.headers();
if (headers.status() != HttpStatus.NO_CONTENT) {
logger.warn("Failed to register {} to Eureka: {}. (status: {}, content: {})",
newInfo.getHostName(), client.uri(), headers.status(), res.contentUtf8());
} else {
logger.info("Registered {} to Eureka: {}", newInfo.getHostName(), client.uri());
scheduleHeartBeat(ctx.eventLoop(), newInfo);
}
return null;
});
}
}
@Test
void registerHeartBeatAndDeregisterAreSent() throws IOException {
final EurekaUpdatingListener listener =
EurekaUpdatingListener.builder(eurekaServer.httpUri())
.instanceId(INSTANCE_ID)
.renewalIntervalSeconds(2)
.appName(APP_NAME)
.build();
final Server application = Server.builder()
.http(0)
.https(0)
.tlsSelfSigned()
.service("/", (ctx, req) -> HttpResponse.of(HttpStatus.OK))
.service("/health", HealthCheckService.of())
.serverListener(listener)
.build();
application.start().join();
await().until(() -> registerContentCaptor.get() != null);
final InstanceInfo instanceInfo = mapper.readValue(registerContentCaptor.get().array(),
InstanceInfo.class);
final InstanceInfo expected = expectedInstanceInfo(application);
assertThat(instanceInfo).isEqualTo(expected);
final RequestHeaders heartBeatHeaders = heartBeatHeadersCaptor.join();
final QueryParams queryParams = QueryParams.fromQueryString(
heartBeatHeaders.path().substring(heartBeatHeaders.path().indexOf('?') + 1));
assertThat(queryParams.get("status")).isEqualTo("UP");
assertThat(queryParams.get("lastDirtyTimestamp"))
.isEqualTo(String.valueOf(instanceInfo.getLastDirtyTimestamp()));
application.stop().join();
final RequestHeaders deregisterHeaders = deregisterHeadersCaptor.join();
assertThat(deregisterHeaders.path()).isEqualTo("/apps/application0/i-00000000");
}
@Test
void makesSureDecoratorsAreConfigured() {
final Function<? super HttpService, ? extends HttpService> decorator = spy(new IdentityFunction());
final AnnotatedServiceRegistrationBean bean = new AnnotatedServiceRegistrationBean()
.setServiceName("test")
.setService(new SimpleService())
.setDecorators(decorator);
final ServerBuilder sb1 = Server.builder();
final DocServiceBuilder dsb1 = DocService.builder();
configureAnnotatedServices(sb1, dsb1, ImmutableList.of(bean),
MeterIdPrefixFunctionFactory.ofDefault(), null);
final Server s1 = sb1.build();
verify(decorator, times(2)).apply(any());
assertThat(service(s1).as(MetricCollectingService.class)).isNotNull();
reset(decorator);
final ServerBuilder sb2 = Server.builder();
final DocServiceBuilder dsb2 = DocService.builder();
configureAnnotatedServices(sb2, dsb2, ImmutableList.of(bean),
null, null);
final Server s2 = sb2.build();
verify(decorator, times(2)).apply(any());
assertThat(getServiceForHttpMethod(sb2.build(), HttpMethod.OPTIONS))
.isInstanceOf(AnnotatedService.class);
}
@Test
void makesSureDecoratedServiceIsAdded() {
final Function<? super HttpService, ? extends HttpService> decorator = spy(new DecoratingFunction());
final AnnotatedServiceRegistrationBean bean = new AnnotatedServiceRegistrationBean()
.setServiceName("test")
.setService(new SimpleService())
.setDecorators(decorator);
final ServerBuilder sb = Server.builder();
final DocServiceBuilder dsb = DocService.builder();
configureAnnotatedServices(sb, dsb, ImmutableList.of(bean), null, null);
final Server s = sb.build();
verify(decorator, times(2)).apply(any());
assertThat(service(s).as(SimpleDecorator.class)).isNotNull();
}
/**
* Stops the {@link Server} asynchronously.
*
* @return the {@link CompletableFuture} that will complete when the {@link Server} is stopped.
*/
public CompletableFuture<Void> stop() {
final Server server = this.server.getAndSet(null);
if (server == null || server.activePorts().isEmpty()) {
return CompletableFuture.completedFuture(null);
}
return server.stop();
}