From bf726d63016197ef03037b6a64346d87653969fe Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sat, 26 May 2018 00:25:41 +0200 Subject: [PATCH 01/12] Java SE Bootstrap API Signed-off-by: Markus KARG --- bundles/jaxrs-ri/pom.xml | 6 + containers/grizzly2-http/pom.xml | 6 + .../httpserver/GrizzlyHttpServer.java | 102 +++++ .../httpserver/GrizzlyHttpServerProvider.java | 41 ++ ...glassfish.jersey.server.spi.ServerProvider | 1 + .../GrizzlyHttpServerProviderTest.java | 154 +++++++ containers/jdk-http/pom.xml | 6 + .../jersey/jdkhttp/JdkHttpServer.java | 93 +++++ .../jersey/jdkhttp/JdkHttpServerFactory.java | 20 +- .../jersey/jdkhttp/JdkHttpServerProvider.java | 42 ++ ...glassfish.jersey.server.spi.ServerProvider | 1 + .../jdkhttp/JdkHttpServerProviderTest.java | 155 +++++++ containers/jetty-http/pom.xml | 6 + .../jersey/jetty/JettyHttpServer.java | 118 ++++++ .../jersey/jetty/JettyHttpServerProvider.java | 41 ++ ...glassfish.jersey.server.spi.ServerProvider | 1 + .../jetty/JettyHttpServerProviderTest.java | 153 +++++++ containers/netty-http/pom.xml | 6 + .../NettyHttpContainerProvider.java | 76 +++- .../netty/httpserver/NettyHttpServer.java | 133 ++++++ .../httpserver/NettyHttpServerProvider.java | 42 ++ ...glassfish.jersey.server.spi.ServerProvider | 1 + .../NettyHttpServerProviderTest.java | 155 +++++++ containers/simple-http/pom.xml | 6 + .../jersey/simple/SimpleContainerFactory.java | 83 +++- .../jersey/simple/SimpleHttpServer.java | 102 +++++ .../simple/SimpleHttpServerProvider.java | 40 ++ .../glassfish/jersey/simple/SimpleServer.java | 3 + ...glassfish.jersey.server.spi.ServerProvider | 1 + .../simple/SimpleHttpServerProviderTest.java | 153 +++++++ core-server/pom.xml | 8 + .../jersey/server/ServerFactory.java | 77 ++++ .../jersey/server/ServerProperties.java | 18 + .../server/internal/RuntimeDelegateImpl.java | 135 ++++++- .../glassfish/jersey/server/spi/Server.java | 103 +++++ .../jersey/server/spi/ServerProvider.java | 87 ++++ .../jersey/server/ServerFactoryTest.java | 109 +++++ .../internal/RuntimeDelegateImplTest.java | 377 +++++++++++++++++- pom.xml | 1 + 39 files changed, 2629 insertions(+), 33 deletions(-) create mode 100644 containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java create mode 100644 containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java create mode 100644 containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider create mode 100644 containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java create mode 100644 containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java create mode 100644 containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java create mode 100644 containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider create mode 100644 containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java create mode 100644 containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java create mode 100644 containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java create mode 100644 containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider create mode 100644 containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java create mode 100644 containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java create mode 100644 containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java create mode 100644 containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider create mode 100644 containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java create mode 100644 containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java create mode 100644 containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java create mode 100644 containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider create mode 100644 containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java create mode 100644 core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java create mode 100644 core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java create mode 100644 core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java create mode 100644 core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java diff --git a/bundles/jaxrs-ri/pom.xml b/bundles/jaxrs-ri/pom.xml index ec7361b01f..bec060ed21 100644 --- a/bundles/jaxrs-ri/pom.xml +++ b/bundles/jaxrs-ri/pom.xml @@ -190,6 +190,12 @@ jakarta.persistence-api provided + + org.eclipse.microprofile.config + microprofile-config-api + ${microprofile.config.version} + provided + diff --git a/containers/grizzly2-http/pom.xml b/containers/grizzly2-http/pom.xml index 46c9b662a0..47589b87e5 100644 --- a/containers/grizzly2-http/pom.xml +++ b/containers/grizzly2-http/pom.xml @@ -41,6 +41,12 @@ org.glassfish.grizzly grizzly-http-server + + org.hamcrest + hamcrest-junit + 2.0.0.0 + test + diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java new file mode 100644 index 0000000000..a08eccdb90 --- /dev/null +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.grizzly2.httpserver; + +import static java.lang.Boolean.TRUE; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.MANDATORY; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.io.IOException; +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; + +/** + * Jersey {@code Server} implementation based on Grizzly {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class GrizzlyHttpServer implements Server { + + private final GrizzlyHttpContainer container; + + private final HttpServer httpServer; + + GrizzlyHttpServer(final Application application, final JAXRS.Configuration configuration) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = configuration.port(); + final String rootPath = configuration.rootPath(); + final SSLContext sslContext = configuration.sslContext(); + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final boolean autoStart = Optional.ofNullable((Boolean) configuration.property(ServerProperties.AUTO_START)) + .orElse(TRUE); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + + this.container = new GrizzlyHttpContainer(application); + this.httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, this.container, "HTTPS".equals(protocol), + new SSLEngineConfigurator(sslContext, false, sslClientAuthentication == OPTIONAL, + sslClientAuthentication == MANDATORY), + autoStart); + } + + @Override + public final GrizzlyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.httpServer.getListener("grizzly").getPort(); + } + + @Override + public final CompletableFuture start() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.start(); + } catch (final IOException e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture stop() { + return CompletableFuture.runAsync(this.httpServer::shutdownNow); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(this.httpServer); + } + +} diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java new file mode 100644 index 0000000000..35926cf750 --- /dev/null +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.grizzly2.httpserver; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +/** + * Server provider for servers based on Grizzly {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class GrizzlyHttpServerProvider implements ServerProvider { + + @Override + public final T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + return GrizzlyHttpServer.class == type || Server.class == type + ? type.cast(new GrizzlyHttpServer(application, configuration)) + : null; + } +} diff --git a/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider b/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider new file mode 100644 index 0000000000..dea5f9097c --- /dev/null +++ b/containers/grizzly2-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider @@ -0,0 +1 @@ +org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerProvider \ No newline at end of file diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java new file mode 100644 index 0000000000..35ee70526c --- /dev/null +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.grizzly2.httpserver; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.GET; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.Path; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +/** + * Unit tests for {@link GrizzlyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class GrizzlyHttpServerProviderTest { + + @Test(timeout = 15000) + public final void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new GrizzlyHttpServerProvider(); + final Resource resource = new Resource(); + final Application application = new Application() { + @Override + public final Set getSingletons() { + return Collections.singleton(resource); + } + }; + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return getPort(); + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return FALSE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + final Object nativeHandle = server.unwrap(Object.class); + final CompletionStage start = server.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = server.container(); + final int port = server.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage stop = server.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(server, is(instanceOf(GrizzlyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(HttpServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(GrizzlyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public final String toString() { + return super.toString(); + } + } + + private static final Logger LOGGER = Logger.getLogger(GrizzlyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 9998; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value is not positive."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + +} diff --git a/containers/jdk-http/pom.xml b/containers/jdk-http/pom.xml index 3497cacba1..d1ffc9675b 100644 --- a/containers/jdk-http/pom.xml +++ b/containers/jdk-http/pom.xml @@ -38,6 +38,12 @@ guava test + + org.hamcrest + hamcrest-junit + 2.0.0.0 + test + diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java new file mode 100644 index 0000000000..b23941f858 --- /dev/null +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jdkhttp; + +import static java.lang.Boolean.TRUE; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.MANDATORY; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; + +import com.sun.net.httpserver.HttpServer; + +/** + * Jersey {@code Server} implementation based on JDK {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JdkHttpServer implements Server { + + private final JdkHttpHandlerContainer container; + + private final HttpServer httpServer; + + JdkHttpServer(final Application application, final JAXRS.Configuration configuration) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = configuration.port(); + final String rootPath = configuration.rootPath(); + final SSLContext sslContext = configuration.sslContext(); + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final boolean autoStart = Optional.ofNullable((Boolean) configuration.property(ServerProperties.AUTO_START)) + .orElse(TRUE); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + + this.container = new JdkHttpHandlerContainer(application); + this.httpServer = JdkHttpServerFactory.createHttpServer(uri, this.container, + "HTTPS".equals(protocol) ? sslContext : null, sslClientAuthentication == OPTIONAL, + sslClientAuthentication == MANDATORY, autoStart); + } + + @Override + public final JdkHttpHandlerContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.httpServer.getAddress().getPort(); + } + + @Override + public final CompletableFuture start() { + return CompletableFuture.runAsync(this.httpServer::start); + } + + @Override + public final CompletableFuture stop() { + return CompletableFuture.runAsync(() -> this.httpServer.stop(0)); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(this.httpServer); + } + +} diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java index 0f1fbb28e9..f91a0a8768 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerFactory.java @@ -26,6 +26,7 @@ import javax.ws.rs.ProcessingException; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder; import org.glassfish.jersey.jdkhttp.internal.LocalizationMessages; @@ -37,6 +38,7 @@ import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpsServer; /** @@ -177,8 +179,17 @@ private static HttpServer createHttpServer(final URI uri, final JdkHttpHandlerCo } private static HttpServer createHttpServer(final URI uri, + final JdkHttpHandlerContainer handler, + final SSLContext sslContext, + final boolean start) { + return createHttpServer(uri, handler, sslContext, false, false, start); + } + + static HttpServer createHttpServer(final URI uri, final JdkHttpHandlerContainer handler, final SSLContext sslContext, + final boolean sslClientAuthWanted, + final boolean sslClientAuthNeeded, final boolean start) { if (uri == null) { throw new IllegalArgumentException(LocalizationMessages.ERROR_CONTAINER_URI_NULL()); @@ -187,7 +198,14 @@ private static HttpServer createHttpServer(final URI uri, final String scheme = uri.getScheme(); final boolean isHttp = "http".equalsIgnoreCase(scheme); final boolean isHttps = "https".equalsIgnoreCase(scheme); - final HttpsConfigurator httpsConfigurator = sslContext != null ? new HttpsConfigurator(sslContext) : null; + final HttpsConfigurator httpsConfigurator = sslContext != null ? new HttpsConfigurator(sslContext) { + public final void configure(final HttpsParameters httpsParameters) { + final SSLParameters sslParameters = sslContext.getDefaultSSLParameters(); + sslParameters.setWantClientAuth(sslClientAuthWanted); + sslParameters.setNeedClientAuth(sslClientAuthNeeded); + httpsParameters.setSSLParameters(sslParameters); + } + } : null; if (isHttp) { if (httpsConfigurator != null) { diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java new file mode 100644 index 0000000000..9a6572090e --- /dev/null +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jdkhttp; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +import com.sun.net.httpserver.HttpServer; + +/** + * Server provider for servers based on JDK {@link HttpServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JdkHttpServerProvider implements ServerProvider { + + @Override + public final T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + return JdkHttpServer.class == type || Server.class == type + ? type.cast(new JdkHttpServer(application, configuration)) + : null; + } +} diff --git a/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider b/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider new file mode 100644 index 0000000000..2d8abc3d23 --- /dev/null +++ b/containers/jdk-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider @@ -0,0 +1 @@ +org.glassfish.jersey.jdkhttp.JdkHttpServerProvider \ No newline at end of file diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java new file mode 100644 index 0000000000..56e8d3c0b8 --- /dev/null +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jdkhttp; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.GET; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.Path; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +import com.sun.net.httpserver.HttpServer; + +/** + * Unit tests for {@link JdkHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JdkHttpServerProviderTest { + + @Test(timeout = 15000) + public final void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new JdkHttpServerProvider(); + final Resource resource = new Resource(); + final Application application = new Application() { + @Override + public final Set getSingletons() { + return Collections.singleton(resource); + } + }; + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return getPort(); + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return FALSE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + final Object nativeHandle = server.unwrap(Object.class); + final CompletionStage start = server.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = server.container(); + final int port = server.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage stop = server.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(server, is(instanceOf(JdkHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(HttpServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(JdkHttpHandlerContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public final String toString() { + return super.toString(); + } + } + + private static final Logger LOGGER = Logger.getLogger(JdkHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 9998; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value is not positive."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + +} diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml index d4c158e8ac..973f2389c7 100644 --- a/containers/jetty-http/pom.xml +++ b/containers/jetty-http/pom.xml @@ -50,6 +50,12 @@ org.eclipse.jetty jetty-continuation + + org.hamcrest + hamcrest-junit + 2.0.0.0 + test + diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java new file mode 100644 index 0000000000..492452108b --- /dev/null +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jetty; + +import static java.lang.Boolean.TRUE; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.MANDATORY; +import static javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication.OPTIONAL; + +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; + +/** + * Jersey {@code Server} implementation based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JettyHttpServer implements Server { + + private final JettyHttpContainer container; + + private final org.eclipse.jetty.server.Server httpServer; + + JettyHttpServer(final Application application, final JAXRS.Configuration configuration) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = configuration.port(); + final String rootPath = configuration.rootPath(); + final SSLContext sslContext = configuration.sslContext(); + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final boolean autoStart = Optional.ofNullable((Boolean) configuration.property(ServerProperties.AUTO_START)) + .orElse(TRUE); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + + final SslContextFactory sslContextFactory; + if ("https".equals(uri.getScheme())) { + sslContextFactory = new SslContextFactory(); + sslContextFactory.setSslContext(sslContext); + sslContextFactory.setWantClientAuth(sslClientAuthentication == OPTIONAL); + sslContextFactory.setNeedClientAuth(sslClientAuthentication == MANDATORY); + } else { + sslContextFactory = null; + } + this.container = ContainerFactory.createContainer(JettyHttpContainer.class, application); + this.httpServer = JettyHttpContainerFactory.createServer(uri, sslContextFactory, this.container, autoStart); + } + + @Override + public final JettyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + final ServerConnector serverConnector = (ServerConnector) this.httpServer.getConnectors()[0]; + final int configuredPort = serverConnector.getPort(); + final int localPort = serverConnector.getLocalPort(); + return localPort < 0 ? configuredPort : localPort; + } + + @Override + public final CompletableFuture start() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.start(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture stop() { + return CompletableFuture.runAsync(() -> { + try { + this.httpServer.stop(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(this.httpServer); + } + +} diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java new file mode 100644 index 0000000000..afeb9c7a20 --- /dev/null +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jetty; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +/** + * Server provider for servers based on Jetty + * {@link org.eclipse.jetty.server.Server Server}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JettyHttpServerProvider implements ServerProvider { + + @Override + public final T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + return JettyHttpServer.class == type || Server.class == type + ? type.cast(new JettyHttpServer(application, configuration)) + : null; + } +} diff --git a/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider b/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider new file mode 100644 index 0000000000..403cc50ccd --- /dev/null +++ b/containers/jetty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider @@ -0,0 +1 @@ +org.glassfish.jersey.jetty.JettyHttpServerProvider \ No newline at end of file diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java new file mode 100644 index 0000000000..a29789dd18 --- /dev/null +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.jetty; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertThat; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.GET; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.Path; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +/** + * Unit tests for {@link JettyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class JettyHttpServerProviderTest { + + @Test(timeout = 15000) + public final void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new JettyHttpServerProvider(); + final Resource resource = new Resource(); + final Application application = new Application() { + @Override + public final Set getSingletons() { + return Collections.singleton(resource); + } + }; + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return getPort(); + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return FALSE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + final Object nativeHandle = server.unwrap(Object.class); + final CompletionStage start = server.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = server.container(); + final int port = server.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage stop = server.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(server, is(instanceOf(JettyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(org.eclipse.jetty.server.Server.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(JettyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public final String toString() { + return super.toString(); + } + } + + private static final Logger LOGGER = Logger.getLogger(JettyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 9998; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value is not positive."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + +} diff --git a/containers/netty-http/pom.xml b/containers/netty-http/pom.xml index a604811e97..8fb7b4e893 100644 --- a/containers/netty-http/pom.xml +++ b/containers/netty-http/pom.xml @@ -42,6 +42,12 @@ jersey-netty-connector ${project.version} + + org.hamcrest + hamcrest-junit + 2.0.0.0 + test + diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java index 124b36ef1e..85d7b96541 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java @@ -58,7 +58,7 @@ public T createContainer(Class type, Application application) throws Proc * Create and start Netty server. * * @param baseUri base uri. - * @param configuration Jersey configuration. + * @param container Jersey container. * @param sslContext Netty SSL context (can be null). * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the * execution will @@ -66,25 +66,59 @@ public T createContainer(Class type, Application application) throws Proc * @return Netty channel instance. * @throws ProcessingException when there is an issue with creating new container. */ - public static Channel createServer(final URI baseUri, final ResourceConfig configuration, SslContext sslContext, + public static Channel createServer(final URI baseUri, final NettyHttpContainer container, SslContext sslContext, final boolean block) throws ProcessingException { + final ServerBootstrap serverBootstrap = createServerBootstrap(baseUri, container, sslContext); + return startServer(getPort(baseUri), container, serverBootstrap, block); + } + + /** + * Create but not start Netty server. + * + * @param baseUri base uri. + * @param container Jersey container. + * @param sslContext Netty SSL context (can be null). + * @return Netty bootstrap instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + static ServerBootstrap createServerBootstrap(final URI baseUri, final NettyHttpContainer container, SslContext sslContext) { + // Configure the server. final EventLoopGroup bossGroup = new NioEventLoopGroup(1); final EventLoopGroup workerGroup = new NioEventLoopGroup(); - final NettyHttpContainer container = new NettyHttpContainer(configuration); - try { - ServerBootstrap b = new ServerBootstrap(); - b.option(ChannelOption.SO_BACKLOG, 1024); - b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new JerseyServerInitializer(baseUri, sslContext, container)); + ServerBootstrap b = new ServerBootstrap(); + b.option(ChannelOption.SO_BACKLOG, 1024); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new JerseyServerInitializer(baseUri, sslContext, container)); - int port = getPort(baseUri); + return b; + } - Channel ch = b.bind(port).sync().channel(); + /** + * Start Netty server. + * + * @param port IP port to listen. + * @param container Jersey container. + * @param serverBootstrap Netty server bootstrap (i. e. prepared but unstarted server instance) + * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the + * execution will + * end immediately after the server is started. + * @return Netty channel instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + static Channel startServer(final int port, final NettyHttpContainer container, final ServerBootstrap serverBootstrap, + final boolean block) + throws ProcessingException { + + try { + final EventLoopGroup bossGroup = serverBootstrap.config().group(); + final EventLoopGroup workerGroup = serverBootstrap.config().childGroup(); + + Channel ch = serverBootstrap.bind(port).sync().channel(); ch.closeFuture().addListener(new GenericFutureListener>() { @Override @@ -107,6 +141,24 @@ public void operationComplete(Future future) throws Exception { } } + /** + * Create and start Netty server. + * + * @param baseUri base uri. + * @param configuration Jersey configuration. + * @param sslContext Netty SSL context (can be null). + * @param block when {@code true}, this method will block until the server is stopped. When {@code false}, the + * execution will + * end immediately after the server is started. + * @return Netty channel instance. + * @throws ProcessingException when there is an issue with creating new container. + */ + public static Channel createServer(final URI baseUri, final ResourceConfig configuration, SslContext sslContext, + final boolean block) + throws ProcessingException { + return createServer(baseUri, new NettyHttpContainer(configuration), sslContext, block); + } + /** * Create and start Netty server. * @@ -172,7 +224,7 @@ public void operationComplete(Future future) throws Exception { } } - private static int getPort(URI uri) { + static int getPort(URI uri) { if (uri.getPort() == -1) { if ("http".equalsIgnoreCase(uri.getScheme())) { return 80; diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java new file mode 100644 index 0000000000..72e66d4549 --- /dev/null +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.netty.httpserver; + +import static java.lang.Boolean.TRUE; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.JdkSslContext; + +/** + * Jersey {@code Server} implementation based on Netty {@link Channel}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class NettyHttpServer implements Server { + + private final NettyHttpContainer container; + + private final ServerBootstrap serverBootstrap; + + private volatile Channel channel; + + private final int port; + + NettyHttpServer(final Application application, final JAXRS.Configuration configuration) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = configuration.port(); + final String rootPath = configuration.rootPath(); + final SSLContext sslContext = configuration.sslContext(); + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final boolean autoStart = Optional.ofNullable((Boolean) configuration.property(ServerProperties.AUTO_START)) + .orElse(TRUE); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + this.port = NettyHttpContainerProvider.getPort(uri); + + this.container = new NettyHttpContainer(application); + this.serverBootstrap = NettyHttpContainerProvider.createServerBootstrap(uri, this.container, + "HTTPS".equals(protocol) + ? new JdkSslContext(sslContext, false, nettyClientAuth(sslClientAuthentication)) + : null); + + if (autoStart) { + this.channel = NettyHttpContainerProvider.startServer(port, this.container, this.serverBootstrap, false); + } + } + + private static final ClientAuth nettyClientAuth( + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication) { + switch (sslClientAuthentication) { + case MANDATORY: + return ClientAuth.REQUIRE; + case OPTIONAL: + return ClientAuth.OPTIONAL; + default: + return ClientAuth.NONE; + } + } + + @Override + public final NettyHttpContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.channel == null ? this.port : ((InetSocketAddress) this.channel.localAddress()).getPort(); + } + + @Override + public final CompletableFuture start() { + return this.channel != null ? CompletableFuture.completedFuture(this.channel) + : CompletableFuture.supplyAsync(() -> { + try { + this.channel = NettyHttpContainerProvider.startServer(this.port, this.container, + this.serverBootstrap, false); + return this.channel; + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture stop() { + return this.channel == null ? CompletableFuture.completedFuture(null) : CompletableFuture.supplyAsync(() -> { + try { + return this.channel.close().get(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(this.channel == null ? this.serverBootstrap : this.channel); + } + +} diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java new file mode 100644 index 0000000000..4376a3af9f --- /dev/null +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.netty.httpserver; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +import io.netty.channel.Channel; + +/** + * Server provider for servers based on Netty {@link Channel}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class NettyHttpServerProvider implements ServerProvider { + + @Override + public final T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + return NettyHttpServer.class == type || Server.class == type + ? type.cast(new NettyHttpServer(application, configuration)) + : null; + } +} diff --git a/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider b/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider new file mode 100644 index 0000000000..61e6e1be11 --- /dev/null +++ b/containers/netty-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider @@ -0,0 +1 @@ +org.glassfish.jersey.netty.httpserver.NettyHttpServerProvider \ No newline at end of file diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java new file mode 100644 index 0000000000..61fbd4241d --- /dev/null +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.netty.httpserver; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertThat; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.GET; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.Path; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; + +/** + * Unit tests for {@link NettyHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class NettyHttpServerProviderTest { + + @Test(timeout = 15000) + public final void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new NettyHttpServerProvider(); + final Resource resource = new Resource(); + final Application application = new Application() { + @Override + public final Set getSingletons() { + return Collections.singleton(resource); + } + }; + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return getPort(); + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return FALSE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + final Object nativeHandle = server.unwrap(Object.class); + final CompletionStage start = server.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = server.container(); + final int port = server.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage stop = server.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(server, is(instanceOf(NettyHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(ServerBootstrap.class))); + assertThat(startResult, is(instanceOf(Channel.class))); + assertThat(container, is(instanceOf(NettyHttpContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public final String toString() { + return super.toString(); + } + } + private static final Logger LOGGER = Logger.getLogger(NettyHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 9998; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value is not positive."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + +} diff --git a/containers/simple-http/pom.xml b/containers/simple-http/pom.xml index 7ef0351d40..0a08a01e6b 100644 --- a/containers/simple-http/pom.xml +++ b/containers/simple-http/pom.xml @@ -49,6 +49,12 @@ org.simpleframework simple-common + + org.hamcrest + hamcrest-junit + 2.0.0.0 + test + diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java index a9dc46d4c7..db8dcdfe66 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java @@ -21,17 +21,19 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.URI; - -import javax.ws.rs.ProcessingException; +import java.util.Optional; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.ProcessingException; import org.glassfish.jersey.internal.util.collection.UnsafeValue; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.simple.internal.LocalizationMessages; - import org.simpleframework.http.core.Container; import org.simpleframework.http.core.ContainerSocketProcessor; +import org.simpleframework.transport.Socket; import org.simpleframework.transport.SocketProcessor; import org.simpleframework.transport.connect.Connection; import org.simpleframework.transport.connect.SocketConnection; @@ -149,7 +151,55 @@ public static SimpleServer create(final URI address, final SSLContext context, public SocketProcessor get() throws IOException { return new ContainerSocketProcessor(container); } - }); + }, true); + } + + /** + * Create a {@link Closeable} that registers an {@link Container} that in turn manages all root + * resource and provider classes found by searching the classes referenced in the java classpath. + * + * @param address the URI to create the http server. The URI scheme must be equal to {@code https} + * . The URI user information and host are ignored. If the URI port is not present then + * port {@value org.glassfish.jersey.server.spi.Container#DEFAULT_HTTPS_PORT} will be used. + * The URI path, query and fragment components are ignored. + * @param context this is the SSL context used for SSL connections. + * @param config the resource configuration. + * @param sslClientAuthentication Secure socket client authentication policy. + * @param start whether the server shall listen to connections immediately + * @return the closeable connection, with the endpoint started. + * @throws ProcessingException thrown when problems during server creation. + * @throws IllegalArgumentException if {@code address} is {@code null}. + */ + public static SimpleServer create(final URI address, final SSLContext context, + final SSLClientAuthentication sslClientAuthentication, final SimpleContainer container, final boolean start) { + return _create(address, context, container, new UnsafeValue() { + @Override + public SocketProcessor get() throws IOException { + return new ContainerSocketProcessor(container) { + @Override + public final void process(final Socket socket) throws IOException { + final SSLEngine sslEngine = socket.getEngine(); + if (sslEngine != null) { + switch (sslClientAuthentication) { + case MANDATORY: { + sslEngine.setNeedClientAuth(true); + break; + } + case OPTIONAL: { + sslEngine.setWantClientAuth(true); + break; + } + default: { + sslEngine.setNeedClientAuth(false); + break; + } + } + } + super.process(socket); + } + }; + } + }, start); } /** @@ -201,12 +251,13 @@ public static SimpleServer create(final URI address, final SSLContext context, public SocketProcessor get() throws IOException { return new ContainerSocketProcessor(container, count, select); } - }); + }, true); } private static SimpleServer _create(final URI address, final SSLContext context, final SimpleContainer container, - final UnsafeValue serverProvider) + final UnsafeValue serverProvider, + final boolean start) throws ProcessingException { if (address == null) { throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); @@ -236,22 +287,26 @@ private static SimpleServer _create(final URI address, final SSLContext context, final SocketProcessor server = serverProvider.get(); connection = new SocketConnection(server, analyzer); + final SimpleServer simpleServer = new SimpleServer() { + private InetSocketAddress socketAddr = listen; - final SocketAddress socketAddr = connection.connect(listen, context); - container.onServerStart(); - - return new SimpleServer() { + @Override + public final void start() throws IOException { + this.socketAddr = (InetSocketAddress) connection.connect(listen, context); + container.onServerStart(); + } @Override public void close() throws IOException { container.onServerStop(); analyzer.stop(); connection.close(); + this.socketAddr = listen; } @Override public int getPort() { - return ((InetSocketAddress) socketAddr).getPort(); + return this.socketAddr.getPort(); } @Override @@ -268,6 +323,12 @@ public void setDebug(boolean enable) { } } }; + + if (start) { + simpleServer.start(); + } + + return simpleServer; } catch (final IOException ex) { throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), ex); } diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java new file mode 100644 index 0000000000..bffed80cff --- /dev/null +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.simple; + +import static java.lang.Boolean.TRUE; + +import java.net.URI; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; + +/** + * Jersey {@code Server} implementation based on Simple framework + * {@link SimpleServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class SimpleHttpServer implements Server { + + private final SimpleContainer container; + + private final SimpleServer simpleServer; + + SimpleHttpServer(final Application application, final JAXRS.Configuration configuration) { + final String protocol = configuration.protocol(); + final String host = configuration.host(); + final int port = configuration.port(); + final String rootPath = configuration.rootPath(); + final SSLContext sslContext = configuration.sslContext(); + final JAXRS.Configuration.SSLClientAuthentication sslClientAuthentication = configuration + .sslClientAuthentication(); + final boolean autoStart = Optional.ofNullable((Boolean) configuration.property(ServerProperties.AUTO_START)) + .orElse(TRUE); + final URI uri = UriBuilder.newInstance().scheme(protocol.toLowerCase()).host(host).port(port).path(rootPath) + .build(); + + this.container = new SimpleContainer(application); + this.simpleServer = SimpleContainerFactory.create(uri, "HTTPS".equals(protocol) ? sslContext : null, + sslClientAuthentication, this.container, autoStart); + } + + @Override + public final SimpleContainer container() { + return this.container; + } + + @Override + public final int port() { + return this.simpleServer.getPort(); + } + + @Override + public final CompletableFuture start() { + return CompletableFuture.runAsync(() -> { + try { + this.simpleServer.start(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final CompletableFuture stop() { + return CompletableFuture.runAsync(() -> { + try { + this.simpleServer.close(); + } catch (final Exception e) { + throw new CompletionException(e); + } + }); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(this.simpleServer); + } + +} diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java new file mode 100644 index 0000000000..9b431bb21e --- /dev/null +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.simple; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +/** + * Server provider for servers based on Simple framework {@link SimpleServer}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class SimpleHttpServerProvider implements ServerProvider { + + @Override + public final T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + return SimpleHttpServer.class == type || Server.class == type + ? type.cast(new SimpleHttpServer(application, configuration)) + : null; + } +} diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java index 02aec75185..b644f7f034 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.simple; import java.io.Closeable; +import java.io.IOException; /** * Simple server facade providing convenient methods to obtain info about the server (i.e. port). @@ -26,6 +27,8 @@ */ public interface SimpleServer extends Closeable { + public void start() throws IOException; + /** * The port the server is listening to for incomming HTTP connections. If the port is not * specified the {@link org.glassfish.jersey.server.spi.Container.DEFAULT_PORT} is used. diff --git a/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider b/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider new file mode 100644 index 0000000000..54d8c5333f --- /dev/null +++ b/containers/simple-http/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ServerProvider @@ -0,0 +1 @@ +org.glassfish.jersey.simple.SimpleHttpServerProvider \ No newline at end of file diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java new file mode 100644 index 0000000000..1f65682219 --- /dev/null +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.simple; + +import static java.lang.Boolean.FALSE; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.GET; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; +import javax.ws.rs.Path; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; + +import org.glassfish.jersey.internal.util.PropertiesHelper; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +/** + * Unit tests for {@link SimpleHttpServerProvider}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class SimpleHttpServerProviderTest { + + @Test(timeout = 15000) + public final void shouldProvideServer() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new SimpleHttpServerProvider(); + final Resource resource = new Resource(); + final Application application = new Application() { + @Override + public final Set getSingletons() { + return Collections.singleton(resource); + } + }; + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return getPort(); + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return FALSE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + final Object nativeHandle = server.unwrap(Object.class); + final CompletionStage start = server.start(); + final Object startResult = start.toCompletableFuture().get(); + final Container container = server.container(); + final int port = server.port(); + final String entity = ClientBuilder.newClient() + .target(UriBuilder.newInstance().scheme("http").host("localhost").port(port).build()).request() + .get(String.class); + final CompletionStage stop = server.stop(); + final Object stopResult = stop.toCompletableFuture().get(); + + // then + assertThat(server, is(instanceOf(SimpleHttpServer.class))); + assertThat(nativeHandle, is(instanceOf(SimpleServer.class))); + assertThat(startResult, is(nullValue())); + assertThat(container, is(instanceOf(SimpleContainer.class))); + assertThat(port, is(greaterThan(0))); + assertThat(entity, is(resource.toString())); + assertThat(stopResult, is(nullValue())); + } + + @Path("/") + protected static final class Resource { + @GET + @Override + public final String toString() { + return super.toString(); + } + } + + private static final Logger LOGGER = Logger.getLogger(SimpleHttpServerProviderTest.class.getName()); + + private static final int DEFAULT_PORT = 9998; + + private static final int getPort() { + final String value = AccessController + .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0) { + throw new NumberFormatException("Value is not positive."); + } + return i; + } catch (final NumberFormatException e) { + LOGGER.log(Level.CONFIG, + "Value of 'jersey.config.test.container.port'" + + " property is not a valid positive integer [" + value + "]." + + " Reverting to default [" + DEFAULT_PORT + "].", + e); + } + } + + return DEFAULT_PORT; + } + +} diff --git a/core-server/pom.xml b/core-server/pom.xml index 3069a25592..64b7b5b770 100644 --- a/core-server/pom.xml +++ b/core-server/pom.xml @@ -170,6 +170,7 @@ jakarta.ws.rs jakarta.ws.rs-api + 2.2-SNAPSHOT @@ -228,6 +229,13 @@ ${project.version} test + + + org.eclipse.microprofile.config + microprofile-config-api + ${microprofile.config.version} + provided + diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java new file mode 100644 index 0000000000..03e286a641 --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.server; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.ProcessingException; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; + +/** + * Factory for creating specific HTTP servers. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class ServerFactory { + + /** + * Prevents instantiation. + */ + private ServerFactory() { + } + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + *

+ * The list of service-providers supporting the {@link ServerProvider} + * service-provider will be iterated over until one returns a non-null server + * instance. + *

+ * + * @param + * the type of the server. + * @param type + * the type of the server. Providers SHOULD support at least + * {@link Server}. + * @param application + * The application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the created server. + * @throws ProcessingException + * if there is an error creating the server. + * @throws IllegalArgumentException + * if no server provider supports the type. + */ + public static T createServer(final Class type, final Application application, + final JAXRS.Configuration configuration) { + for (final ServerProvider serverProvider : ServiceFinder.find(ServerProvider.class)) { + final T server = serverProvider.createServer(type, application, configuration); + if (server != null) { + return server; + } + } + + throw new IllegalArgumentException("No server provider supports the type " + type); + } + +} diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java index fafb73a18e..36961933fd 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java @@ -24,6 +24,7 @@ import org.glassfish.jersey.internal.util.PropertiesClass; import org.glassfish.jersey.internal.util.PropertiesHelper; import org.glassfish.jersey.internal.util.PropertyAlias; +import org.glassfish.jersey.server.spi.Server; /** @@ -37,6 +38,23 @@ @PropertiesClass public final class ServerProperties { + /** + * Defines the implementation of {@link Server} to bootstrap. + *

+ * By default auto-selects the first server provider found. + *

+ */ + public static final String HTTP_SERVER_CLASS = "jersey.config.server.httpServerClass"; + + /** + * Whether to automatically startup {@link Server} at bootstrap. + *

+ * By default, servers are immediately listening to connections after bootstrap, + * so no explicit invocation of {@link Server#start()} is needed. + *

+ */ + public static final String AUTO_START = "jersey.config.server.autoStart"; + /** * Defines one or more packages that contain application-specific resources and * providers. diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java index f4fe50c02d..9dba7c7ca1 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java @@ -16,20 +16,39 @@ package org.glassfish.jersey.server.internal; +import static java.lang.Boolean.TRUE; + +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.function.BiFunction; +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration; +import javax.ws.rs.JAXRS.Configuration.Builder; +import javax.ws.rs.JAXRS.Configuration.SSLClientAuthentication; import javax.ws.rs.core.Application; import javax.ws.rs.JAXRS; import javax.ws.rs.JAXRS.Instance; +import org.eclipse.microprofile.config.Config; import org.glassfish.jersey.internal.AbstractRuntimeDelegate; import org.glassfish.jersey.message.internal.MessagingBinders; import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ServerFactory; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Server; /** * Server-side implementation of JAX-RS {@link javax.ws.rs.ext.RuntimeDelegate}. - * This overrides the default implementation of {@link javax.ws.rs.ext.RuntimeDelegate} from - * jersey-common which does not implement {@link #createEndpoint(javax.ws.rs.core.Application, java.lang.Class)} + * This overrides the default implementation of + * {@link javax.ws.rs.ext.RuntimeDelegate} from jersey-common which does not + * implement + * {@link #createEndpoint(javax.ws.rs.core.Application, java.lang.Class)} * method. * * @author Jakub Podlesak @@ -43,7 +62,7 @@ public RuntimeDelegateImpl() { } @Override - public T createEndpoint(Application application, Class endpointType) + public T createEndpoint(final Application application, final Class endpointType) throws IllegalArgumentException, UnsupportedOperationException { if (application == null) { throw new IllegalArgumentException("application is null."); @@ -51,14 +70,118 @@ public T createEndpoint(Application application, Class endpointType) return ContainerFactory.createContainer(endpointType, application); } + private static final Map> PROPERTY_TYPES = new HashMap<>(); + + static { + PROPERTY_TYPES.put(JAXRS.Configuration.PROTOCOL, String.class); + PROPERTY_TYPES.put(JAXRS.Configuration.HOST, String.class); + PROPERTY_TYPES.put(JAXRS.Configuration.PORT, Integer.class); + PROPERTY_TYPES.put(JAXRS.Configuration.ROOT_PATH, String.class); + PROPERTY_TYPES.put(JAXRS.Configuration.SSL_CONTEXT, SSLContext.class); + PROPERTY_TYPES.put(JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION, SSLClientAuthentication.class); + PROPERTY_TYPES.put(ServerProperties.HTTP_SERVER_CLASS, Class.class); + PROPERTY_TYPES.put(ServerProperties.AUTO_START, Boolean.class); + } + @Override public JAXRS.Configuration.Builder createConfigurationBuilder() { - throw new UnsupportedOperationException(); + return new JAXRS.Configuration.Builder() { + private final Map properties = new HashMap<>(); + + { + this.properties.put(JAXRS.Configuration.PROTOCOL, "HTTP"); + this.properties.put(JAXRS.Configuration.HOST, "localhost"); + this.properties.put(JAXRS.Configuration.PORT, -1); // Auto-select port 80 for HTTP or 443 for HTTPS + this.properties.put(JAXRS.Configuration.ROOT_PATH, "/"); + this.properties.put(ServerProperties.HTTP_SERVER_CLASS, Server.class); // Auto-select first provider + try { + this.properties.put(JAXRS.Configuration.SSL_CONTEXT, SSLContext.getDefault()); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + this.properties.put(JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION, + JAXRS.Configuration.SSLClientAuthentication.NONE); + this.properties.put(ServerProperties.AUTO_START, TRUE); + } + + @Override + public final JAXRS.Configuration.Builder property(final String name, final Object value) { + this.properties.put(name, value); + return this; + } + + @SuppressWarnings("unchecked") + @Override + public final Builder from(final BiFunction, Optional> configProvider) { + PROPERTY_TYPES.forEach( + (propertyName, propertyType) -> configProvider.apply(propertyName, (Class) propertyType) + .ifPresent(propertyValue -> this.properties.put(propertyName, propertyValue))); + return this; + } + + @Override + public final Builder from(final Object externalConfig) { + if (externalConfig instanceof Config) { + return this.from((Config) externalConfig); + } + + return this; + } + + private final Builder from(final Config config) { + return this.from(config::getOptionalValue); + } + + @Override + public final JAXRS.Configuration build() { + return this.properties::get; + } + }; } + @SuppressWarnings("unchecked") @Override - public CompletionStage bootstrap(Application application, JAXRS.Configuration configuration) { - throw new UnsupportedOperationException(); + public CompletableFuture bootstrap(final Application application, + final JAXRS.Configuration configuration) { + return CompletableFuture.supplyAsync(() -> { + final Class httpServerClass = (Class) configuration + .property(ServerProperties.HTTP_SERVER_CLASS); + + return new JAXRS.Instance() { + private final Server server = ServerFactory.createServer(httpServerClass, application, configuration); + + @Override + public final Configuration configuration() { + return name -> { + switch (name) { + case JAXRS.Configuration.PORT: + return server.port(); + case ServerProperties.HTTP_SERVER_CLASS: + return server.getClass(); + default: + return configuration.property(name); + } + }; + } + + @Override + public final CompletionStage stop() { + return this.server.stop().thenApply(nativeResult -> new StopResult() { + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.cast(nativeResult); + } + }); + } + + @Override + public final T unwrap(final Class nativeClass) { + return nativeClass.isInstance(this.server) ? nativeClass.cast(this.server) + : this.server.unwrap(nativeClass); + } + }; + }); } } diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java new file mode 100644 index 0000000000..07a1724b94 --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.server.spi; + +import java.util.concurrent.CompletionStage; + +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.spi.Contract; + +/** + * Jersey service contract for self-contained servers. + *

+ * Runs a self-contained {@link Application} in a {@link Container} using an + * HTTP server implicitly started and stopped together with the application. + *

+ * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +@Contract +@ConstrainedTo(RuntimeType.SERVER) +public interface Server { + + /** + * @return container in which the application lives. + */ + public Container container(); + + /** + * @return IP port the application listens to for requests. + */ + public int port(); + + /** + * Initiates server bootstrap. + *

+ * Startup happens in background. The completion stage produces a native startup + * result. + *

+ *

+ * Portable applications should not expect any particular result type, as it is + * implementation-specific. + *

+ * + * @return A {@link CompletionStage} providing a native startup result of the + * bootstrap process. The native result MAY be {@code null}. + */ + public CompletionStage start(); + + /** + * Initiates server shutdown. + *

+ * Shutdown happens in background. The completion stage produces a native + * shutdown result. + *

+ *

+ * Portable applications should not expect any particular result type, as it is + * implementation-specific. + *

+ * + * @return A {@link CompletionStage} providing a native shutdown result of the + * shutdown process. The native result MAY be {@code null}. + */ + public CompletionStage stop(); + + /** + * Provides access to the native handle(s) of the server, if it holds at least + * one. + *

+ * Implementations MAY use native handles to identify the server instance, and / + * or use those to communicate with and control the instance. Whether or not + * such handles exist, and their respective data types, is + * implementation-specific. + *

+ *

+ * Portable applications should not invoke this method, as the types of + * supported handles are implementation-specific. + *

+ * + * @param nativeClass + * The class of the native handle. + * @return The native handle, or {@code null} if no handle of this type exists. + */ + public T unwrap(Class nativeClass); + +} diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java new file mode 100644 index 0000000000..8455e87523 --- /dev/null +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.server.spi; + +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.JAXRS; +import javax.ws.rs.ProcessingException; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.spi.Contract; + +/** + * Service-provider interface for creating server instances. + * + * If supported by the provider, a server instance of the requested Java type + * will be created. + *

+ * The created server uses an internally created {@link Container} which is + * responsible for listening on a communication channel provided by the server + * for new client requests, dispatching these requests to the registered + * {@link ApplicationHandler Jersey application handler} using the handler's + * {@link ApplicationHandler#handle(org.glassfish.jersey.server.ContainerRequest) + * handle(requestContext)} method and sending the responses provided by the + * application back to the client. + *

+ *

+ * A provider shall support a one-to-one mapping between a type, provided the + * type is not {@link Object}. A provider may also support mapping of sub-types + * of a type (provided the type is not {@code Object}). It is expected that each + * provider supports mapping for distinct set of types and subtypes so that + * different providers do not conflict with each other. In addition, a provider + * SHOULD support the super type {@link Server} to participate in auto-selection + * of providers (in this case the first supporting provider found is + * used). + *

+ *

+ * An implementation can identify itself by placing a Java service provider + * configuration file (if not already present) - + * {@code org.glassfish.jersey.server.spi.ServerProvider} - in the resource + * directory {@code META-INF/services}, and adding the fully qualified + * service-provider-class of the implementation in the file. + *

+ * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +@Contract +@ConstrainedTo(RuntimeType.SERVER) +public interface ServerProvider { + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * + * @param + * the type of the server. + * @param type + * the type of the server. Providers SHOULD support at least + * {@link Server}. + * @param application + * The application to host. + * @param configuration + * The configuration (host, port, etc.) to be used for bootstrapping. + * @return the server, otherwise {@code null} if the provider does not support + * the requested {@code type}. + * @throws ProcessingException + * if there is an error creating the server. + */ + public T createServer(Class type, Application application, JAXRS.Configuration configuration) + throws ProcessingException; +} diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java new file mode 100644 index 0000000000..362d001186 --- /dev/null +++ b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Markus KARG. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.server; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.theInstance; +import static org.junit.Assert.assertThat; + +import java.util.Collections; +import java.util.Iterator; +import java.util.concurrent.CompletionStage; + +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration; +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.Test; + +/** + * Unit tests for {@link ServerFactory}. + * + * @author Markus KARG (markus@headcrashing.eu) + * @since 2.28 + */ +public final class ServerFactoryTest { + + @Test + public final void shouldBuildServer() { + // given + final Application mockApplication = new Application(); + final JAXRS.Configuration mockConfiguration = name -> null; + final Server mockServer = new Server() { + + @Override + public final Container container() { + return null; + } + + @Override + public final int port() { + return 0; + } + + @Override + public final CompletionStage start() { + return null; + } + + @Override + public final CompletionStage stop() { + return null; + } + + @Override + public final T unwrap(final Class nativeClass) { + return null; + } + }; + ServiceFinder.setIteratorProvider(new ServiceIteratorProvider() { + + @Override + public final Iterator createIterator(final Class service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return Collections.singleton(service.cast(new ServerProvider() { + + @Override + public final U createServer(final Class type, final Application application, + final Configuration configuration) { + return application == mockApplication && configuration == mockConfiguration + ? type.cast(mockServer) + : null; + } + })).iterator(); + } + + @Override + public final Iterator> createClassIterator(final Class service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return null; + } + }); + + // when + final Server server = ServerFactory.createServer(Server.class, mockApplication, mockConfiguration); + + // then + assertThat(server, is(theInstance(mockServer))); + } + +} diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java index 57d9668f0b..f8b9076cf5 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java @@ -16,17 +16,48 @@ package org.glassfish.jersey.server.internal; +import static java.lang.Boolean.FALSE; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.theInstance; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.function.BiFunction; + +import javax.net.ssl.SSLContext; +import javax.ws.rs.JAXRS; +import javax.ws.rs.JAXRS.Configuration; import javax.ws.rs.core.Application; import javax.ws.rs.ext.RuntimeDelegate; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.glassfish.jersey.internal.ServiceFinder; +import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; +import org.glassfish.jersey.server.ApplicationHandler; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.Server; +import org.glassfish.jersey.server.spi.ServerProvider; import org.junit.Test; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; /** - * Unit test that checks that the right RuntimeDelegateImpl is loaded by JAX-RS. + * Unit tests for {@link RuntimeDelegate}. * * @author Martin Matula + * @author Markus KARG (markus@headcrashing.eu) */ public class RuntimeDelegateImplTest { @@ -43,8 +74,348 @@ public void testCreateEndpoint() { } } + /** + * Checks that the right RuntimeDelegateImpl is loaded by JAX-RS. + */ @Test public void testRuntimeDelegateInstance() { assertSame(RuntimeDelegateImpl.class, RuntimeDelegate.getInstance().getClass()); } + + @Test + public final void shouldCreateConfigurationBuilder() { + // given + final RuntimeDelegate runtimeDelegate = new RuntimeDelegateImpl(); + + // when + final JAXRS.Configuration.Builder configurationBuilder = runtimeDelegate.createConfigurationBuilder(); + + // then + assertThat(configurationBuilder, is(notNullValue())); + } + + @Test + public final void shouldBuildDefaultConfiguration() throws NoSuchAlgorithmException { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + + // when + final JAXRS.Configuration configuration = configurationBuilder.build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.property(JAXRS.Configuration.PROTOCOL), is("HTTP")); + assertThat(configuration.property(JAXRS.Configuration.HOST), is("localhost")); + assertThat(configuration.property(JAXRS.Configuration.PORT), is(JAXRS.Configuration.DEFAULT_PORT)); + assertThat(configuration.property(JAXRS.Configuration.ROOT_PATH), is("/")); + assertThat(configuration.property(JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION), + is(JAXRS.Configuration.SSLClientAuthentication.NONE)); + assertThat(configuration.property(JAXRS.Configuration.SSL_CONTEXT), is(theInstance(SSLContext.getDefault()))); + assertThat(configuration.protocol(), is("HTTP")); + assertThat(configuration.host(), is("localhost")); + assertThat(configuration.port(), is(JAXRS.Configuration.DEFAULT_PORT)); + assertThat(configuration.rootPath(), is("/")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.NONE)); + assertThat(configuration.sslContext(), is(theInstance(SSLContext.getDefault()))); + } + + @Test + public final void shouldBuildConfigurationContainingCustomProperties() { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + + // when + final JAXRS.Configuration configuration = configurationBuilder.property("property", "value").build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.property("property"), is("value")); + } + + @Test + public final void shouldBuildCustomConfigurationUsingNamedStandardProperties() throws NoSuchAlgorithmException { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + final SSLContext mockSslContext = new SSLContext(null, null, null) { + }; + + // when + final JAXRS.Configuration configuration = configurationBuilder.property(JAXRS.Configuration.PROTOCOL, "HTTPS") + .property(JAXRS.Configuration.HOST, "hostname").property(JAXRS.Configuration.PORT, 8080) + .property(JAXRS.Configuration.ROOT_PATH, "path") + .property(JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION, + JAXRS.Configuration.SSLClientAuthentication.OPTIONAL) + .property(JAXRS.Configuration.SSL_CONTEXT, mockSslContext).build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.protocol(), is("HTTPS")); + assertThat(configuration.host(), is("hostname")); + assertThat(configuration.port(), is(8080)); + assertThat(configuration.rootPath(), is("path")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); + } + + @Test + public final void shouldBuildCustomConfigurationUsingConvenienceMethods() throws NoSuchAlgorithmException { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + final SSLContext mockSslContext = new SSLContext(null, null, null) { + }; + + // when + final JAXRS.Configuration configuration = configurationBuilder.protocol("HTTPS").host("hostname").port(8080) + .rootPath("path").sslClientAuthentication(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL) + .sslContext(mockSslContext).build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.protocol(), is("HTTPS")); + assertThat(configuration.host(), is("hostname")); + assertThat(configuration.port(), is(8080)); + assertThat(configuration.rootPath(), is("path")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); + } + + @Test + public final void shouldBuildCustomConfigurationFromPropertiesProvider() { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + final SSLContext mockSslContext = new SSLContext(null, null, null) { + }; + final Class mockServerClass = Server.class; + final BiFunction, Optional> propertiesProvider = (propertyName, propertyType) -> { + if (JAXRS.Configuration.PROTOCOL.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of("HTTPS"); + } + if (JAXRS.Configuration.HOST.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of("hostname"); + } + if (JAXRS.Configuration.PORT.equals(propertyName) && Integer.class.equals(propertyType)) { + return Optional.of(8080); + } + if (JAXRS.Configuration.ROOT_PATH.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of("path"); + } + if (JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION.equals(propertyName) + && JAXRS.Configuration.SSLClientAuthentication.class.equals(propertyType)) { + return Optional.of(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL); + } + if (JAXRS.Configuration.SSL_CONTEXT.equals(propertyName) && SSLContext.class.equals(propertyType)) { + return Optional.of(mockSslContext); + } + if (ServerProperties.HTTP_SERVER_CLASS.equals(propertyName) && Class.class.equals(propertyType)) { + return Optional.of(mockServerClass); + } + if (ServerProperties.AUTO_START.equals(propertyName) && Boolean.class.equals(propertyType)) { + return Optional.of(FALSE); + } + return Optional.empty(); + }; + + // when + final JAXRS.Configuration configuration = configurationBuilder.from(propertiesProvider).build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.protocol(), is("HTTPS")); + assertThat(configuration.host(), is("hostname")); + assertThat(configuration.port(), is(8080)); + assertThat(configuration.rootPath(), is("path")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); + assertThat(configuration.property(ServerProperties.HTTP_SERVER_CLASS), is(theInstance(mockServerClass))); + assertThat(configuration.property(ServerProperties.AUTO_START), is(FALSE)); + } + + @Test + public final void shouldBuildCustomConfigurationFromMicroprofileConfig() { + // given + final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); + final SSLContext mockSslContext = new SSLContext(null, null, null) { + }; + final Class mockServerClass = Server.class; + final Config config = new Config() { + @Override + public final T getValue(final String propertyName, final Class propertyType) { + return null; + } + + @Override + public final Optional getOptionalValue(final String propertyName, final Class propertyType) { + if (JAXRS.Configuration.PROTOCOL.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of(propertyType.cast("HTTPS")); + } + if (JAXRS.Configuration.HOST.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of(propertyType.cast("hostname")); + } + if (JAXRS.Configuration.PORT.equals(propertyName) && Integer.class.equals(propertyType)) { + return Optional.of(propertyType.cast(8080)); + } + if (JAXRS.Configuration.ROOT_PATH.equals(propertyName) && String.class.equals(propertyType)) { + return Optional.of(propertyType.cast("path")); + } + if (JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION.equals(propertyName) + && JAXRS.Configuration.SSLClientAuthentication.class.equals(propertyType)) { + return Optional.of(propertyType.cast(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + } + if (JAXRS.Configuration.SSL_CONTEXT.equals(propertyName) && SSLContext.class.equals(propertyType)) { + return Optional.of(propertyType.cast(mockSslContext)); + } + if (ServerProperties.HTTP_SERVER_CLASS.equals(propertyName) && Class.class.equals(propertyType)) { + return Optional.of(propertyType.cast(mockServerClass)); + } + if (ServerProperties.AUTO_START.equals(propertyName) && Boolean.class.equals(propertyType)) { + return Optional.of(propertyType.cast(FALSE)); + } + return Optional.empty(); + } + + @Override + public final Iterable getPropertyNames() { + return null; + } + + @Override + public final Iterable getConfigSources() { + return null; + } + }; + + // when + final JAXRS.Configuration configuration = configurationBuilder.from(config).build(); + + // then + assertThat(configuration, is(notNullValue())); + assertThat(configuration.protocol(), is("HTTPS")); + assertThat(configuration.host(), is("hostname")); + assertThat(configuration.port(), is(8080)); + assertThat(configuration.rootPath(), is("path")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); + assertThat(configuration.property(ServerProperties.HTTP_SERVER_CLASS), is(theInstance(mockServerClass))); + assertThat(configuration.property(ServerProperties.AUTO_START), is(FALSE)); + } + + @Test + public final void shouldBootstrapApplication() throws InterruptedException, ExecutionException, TimeoutException { + // given + final Container mockContainer = new Container() { + @Override + public final ResourceConfig getConfiguration() { + return null; + } + + @Override + public final ApplicationHandler getApplicationHandler() { + return null; + } + + @Override + public final void reload() { + } + + @Override + public final void reload(final ResourceConfig configuration) { + } + }; + final Server mockServer = new Server() { + @Override + public final Container container() { + return mockContainer; + } + + @Override + public final int port() { + return 8888; + } + + @Override + public final CompletionStage start() { + return CompletableFuture.completedFuture(null); + } + + @Override + public final CompletionStage stop() { + return CompletableFuture.completedFuture(null); + } + + @Override + public final T unwrap(final Class nativeClass) { + return null; + } + }; + final RuntimeDelegate runtimeDelegate = new RuntimeDelegateImpl(); + final Application mockApplication = new Application(); + final SSLContext mockSslContext = new SSLContext(null, null, null) { + }; + final JAXRS.Configuration mockConfiguration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTPS"; + case JAXRS.Configuration.HOST: + return "hostname"; + case JAXRS.Configuration.PORT: + return JAXRS.Configuration.DEFAULT_PORT; + case JAXRS.Configuration.ROOT_PATH: + return "path"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return JAXRS.Configuration.SSLClientAuthentication.OPTIONAL; + case JAXRS.Configuration.SSL_CONTEXT: + return mockSslContext; + case ServerProperties.HTTP_SERVER_CLASS: + return Server.class; + default: + return null; + } + }; + ServiceFinder.setIteratorProvider(new ServiceIteratorProvider() { + @Override + public final Iterator createIterator(final Class service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return Collections.singleton(service.cast(new ServerProvider() { + @Override + public final U createServer(final Class type, final Application application, + final Configuration configuration) { + return application == mockApplication && configuration == mockConfiguration + ? type.cast(mockServer) + : null; + } + })).iterator(); + } + + @Override + public final Iterator> createClassIterator(final Class service, final String serviceName, + final ClassLoader loader, final boolean ignoreOnClassNotFound) { + return null; + } + }); + + // when + final CompletionStage bootstrapStage = runtimeDelegate.bootstrap(mockApplication, + mockConfiguration); + final JAXRS.Instance instance = bootstrapStage.toCompletableFuture().get(15, SECONDS); + final Configuration configuration = instance.configuration(); + final Server server = instance.unwrap(Server.class); + final Container container = server.container(); + final CompletionStage stopStage = instance.stop(); + final Object stopResult = stopStage.toCompletableFuture().get(15, SECONDS); + + // then + assertThat(instance, is(notNullValue())); + assertThat(configuration, is(notNullValue())); + assertThat(configuration.protocol(), is("HTTPS")); + assertThat(configuration.host(), is("hostname")); + assertThat(configuration.port(), is(8888)); + assertThat(configuration.rootPath(), is("path")); + assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); + assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); + assertThat(configuration.property(ServerProperties.HTTP_SERVER_CLASS), is(theInstance(mockServer.getClass()))); + assertThat(server, is(theInstance(mockServer))); + assertThat(container, is(theInstance(mockContainer))); + assertThat(stopResult, is(notNullValue())); + } + } diff --git a/pom.xml b/pom.xml index 8810f3b9a3..e184e20c40 100644 --- a/pom.xml +++ b/pom.xml @@ -2041,5 +2041,6 @@ 2.11.0 1.0.3 false + 1.3 From 373feea7b2634e1fc6253a67443bbfeb26ca5bf7 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 26 Aug 2018 16:57:12 +0200 Subject: [PATCH 02/12] Support for free IP port scan Signed-off-by: Markus KARG --- .../GrizzlyHttpServerProviderTest.java | 38 +++++++++++++++++++ .../jdkhttp/JdkHttpServerProviderTest.java | 38 +++++++++++++++++++ .../jetty/JettyHttpServerProviderTest.java | 38 +++++++++++++++++++ .../NettyHttpServerProviderTest.java | 38 +++++++++++++++++++ .../simple/SimpleHttpServerProviderTest.java | 38 +++++++++++++++++++ 5 files changed, 190 insertions(+) diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index 35ee70526c..88daabaac0 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.grizzly2.httpserver; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.greaterThan; @@ -151,4 +152,41 @@ private static final int getPort() { return DEFAULT_PORT; } + @Test(timeout = 15000) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new GrizzlyHttpServerProvider(); + final Application application = new Application(); + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return 0; + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return TRUE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + + // then + assertThat(server.port(), is(greaterThan(0))); + } + } diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index 56e8d3c0b8..88287f476b 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.jdkhttp; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.greaterThan; @@ -152,4 +153,41 @@ private static final int getPort() { return DEFAULT_PORT; } + @Test(timeout = 15000) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new JdkHttpServerProvider(); + final Application application = new Application(); + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return 0; + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return TRUE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + + // then + assertThat(server.port(), is(greaterThan(0))); + } + } diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index a29789dd18..6f1a3a4d48 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.jetty; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; @@ -150,4 +151,41 @@ private static final int getPort() { return DEFAULT_PORT; } + @Test(timeout = 15000) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new JettyHttpServerProvider(); + final Application application = new Application(); + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return 0; + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return TRUE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + + // then + assertThat(server.port(), is(greaterThan(0))); + } + } diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index 61fbd4241d..a34fbe2474 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.netty.httpserver; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; @@ -152,4 +153,41 @@ private static final int getPort() { return DEFAULT_PORT; } + @Test(timeout = 15000) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new NettyHttpServerProvider(); + final Application application = new Application(); + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return 0; + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return TRUE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + + // then + assertThat(server.port(), is(greaterThan(0))); + } + } diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index 1f65682219..c2a98540c7 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -17,6 +17,7 @@ package org.glassfish.jersey.simple; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.greaterThan; @@ -150,4 +151,41 @@ private static final int getPort() { return DEFAULT_PORT; } + @Test(timeout = 15000) + public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + // given + final ServerProvider serverProvider = new SimpleHttpServerProvider(); + final Application application = new Application(); + final JAXRS.Configuration configuration = name -> { + switch (name) { + case JAXRS.Configuration.PROTOCOL: + return "HTTP"; + case JAXRS.Configuration.HOST: + return "localhost"; + case JAXRS.Configuration.PORT: + return 0; + case JAXRS.Configuration.ROOT_PATH: + return "/"; + case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case JAXRS.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.AUTO_START: + return TRUE; + default: + return null; + } + }; + + // when + final Server server = serverProvider.createServer(Server.class, application, configuration); + + // then + assertThat(server.port(), is(greaterThan(0))); + } + } From acd82fee58c4e226897c2abd5eeb1f210faa302f Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 26 Aug 2018 18:57:39 +0200 Subject: [PATCH 03/12] Tests do free port scan with jersey.config.test.container.port=0 Signed-off-by: Markus KARG --- .../GrizzlyHttpServerProviderTest.java | 6 ++-- .../jdkhttp/AbstractJdkHttpServerTester.java | 23 +++++++++++--- .../jdkhttp/JdkHttpServerProviderTest.java | 6 ++-- .../jersey/jdkhttp/JdkHttpsServerTest.java | 31 +++++++------------ .../jetty/AbstractJettyServerTester.java | 15 ++++++--- .../jetty/JettyHttpServerProviderTest.java | 6 ++-- .../NettyHttpServerProviderTest.java | 6 ++-- .../simple/AbstractSimpleServerTester.java | 18 ++++++----- .../simple/SimpleHttpServerProviderTest.java | 6 ++-- 9 files changed, 66 insertions(+), 51 deletions(-) diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index 88daabaac0..9d08f16699 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -136,14 +136,14 @@ private static final int getPort() { if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value is not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (final NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java index 24998f949e..3c8f946354 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java @@ -21,6 +21,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.net.ssl.SSLContext; import javax.ws.rs.core.UriBuilder; import com.sun.net.httpserver.HttpServer; @@ -47,20 +48,24 @@ public abstract class AbstractJdkHttpServerTester { * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return server.getAddress().getPort(); + } + final String value = AccessController.doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -79,14 +84,22 @@ public void startServer(Class... resources) { config.register(LoggingFeature.class); final URI baseUri = getBaseUri(); server = JdkHttpServerFactory.createHttpServer(baseUri, config); - LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = JdkHttpServerFactory.createHttpServer(baseUri, config); - LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + getBaseUri()); + } + + public HttpServer startServer(final URI uri, final ResourceConfig config, + final SSLContext sslContext, final boolean start) { + config.register(LoggingFeature.class); + server = JdkHttpServerFactory.createHttpServer(uri, config, sslContext, start); + LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + UriBuilder.fromUri(uri).port(getPort()).build()); + return server; } public URI getBaseUri() { diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index 88287f476b..f942a99537 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -137,14 +137,14 @@ private static final int getPort() { if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value is not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (final NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java index 180f2bc8b4..5fe94cbdf1 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java @@ -64,9 +64,6 @@ public class JdkHttpsServerTest extends AbstractJdkHttpServerTester { private static final String TRUSTSTORE_SERVER_FILE = "./truststore_server"; private static final String TRUSTSTORE_SERVER_PWD = "asdfgh"; - private HttpServer server; - private final URI httpsUri = UriBuilder.fromUri("https://localhost/").port(getPort()).build(); - private final URI httpUri = UriBuilder.fromUri("http://localhost/").port(getPort()).build(); private final ResourceConfig rc = new ResourceConfig(TestResource.class); @Path("/testHttps") @@ -83,7 +80,7 @@ public String get() { */ @Test public void testCreateHttpsServerNoSslContext() throws Exception { - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, false); + HttpServer server = startServer(getHttpsUri(), rc, null, false); assertThat(server, instanceOf(HttpsServer.class)); } @@ -93,7 +90,7 @@ public void testCreateHttpsServerNoSslContext() throws Exception { */ @Test(expected = IllegalArgumentException.class) public void testStartHttpServerNoSslContext() throws Exception { - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, true); + startServer(getHttpsUri(), rc, null, true); } /** @@ -103,13 +100,13 @@ public void testStartHttpServerNoSslContext() throws Exception { */ @Test(expected = SSLHandshakeException.class) public void testCreateHttpsServerDefaultSslContext() throws Throwable { - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, SSLContext.getDefault(), true); + HttpServer server = startServer(getHttpsUri(), rc, SSLContext.getDefault(), true); assertThat(server, instanceOf(HttpsServer.class)); // access the https server with not configured client final Client client = ClientBuilder.newBuilder().newClient(); try { - client.target(httpsUri).path("testHttps").request().get(String.class); + client.target(UriBuilder.fromUri("https://localhost/").port(getPort())).path("testHttps").request().get(String.class); } catch (final ProcessingException e) { throw e.getCause(); } @@ -122,13 +119,13 @@ public void testCreateHttpsServerDefaultSslContext() throws Throwable { */ @Test(expected = IOException.class) public void testHttpsServerNoSslContextDelayedStart() throws Throwable { - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, false); + HttpServer server = startServer(getHttpsUri(), rc, null, false); assertThat(server, instanceOf(HttpsServer.class)); server.start(); final Client client = ClientBuilder.newBuilder().newClient(); try { - client.target(httpsUri).path("testHttps").request().get(String.class); + client.target(getHttpsUri()).path("testHttps").request().get(String.class); } catch (final ProcessingException e) { throw e.getCause(); } @@ -140,7 +137,7 @@ public void testHttpsServerNoSslContextDelayedStart() throws Throwable { */ @Test(expected = IllegalStateException.class) public void testConfigureSslContextAfterStart() throws Throwable { - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, null, false); + HttpServer server = startServer(getHttpsUri(), rc, null, false); assertThat(server, instanceOf(HttpsServer.class)); server.start(); ((HttpsServer) server).setHttpsConfigurator(new HttpsConfigurator(getServerSslContext())); @@ -154,14 +151,14 @@ public void testConfigureSslContextAfterStart() throws Throwable { public void testCreateHttpsServerRoundTrip() throws IOException { final SSLContext serverSslContext = getServerSslContext(); - server = JdkHttpServerFactory.createHttpServer(httpsUri, rc, serverSslContext, true); + HttpServer server = startServer(getHttpsUri(), rc, serverSslContext, true); final SSLContext foundContext = ((HttpsServer) server).getHttpsConfigurator().getSSLContext(); assertEquals(serverSslContext, foundContext); final SSLContext clientSslContext = getClientSslContext(); final Client client = ClientBuilder.newBuilder().sslContext(clientSslContext).build(); - final String response = client.target(httpsUri).path("testHttps").request().get(String.class); + final String response = client.target(UriBuilder.fromUri("https://localhost/").port(getPort())).path("testHttps").request().get(String.class); assertEquals("test", response); } @@ -172,7 +169,7 @@ public void testCreateHttpsServerRoundTrip() throws IOException { */ @Test public void testHttpWithSsl() throws IOException { - server = JdkHttpServerFactory.createHttpServer(httpUri, rc, getServerSslContext(), true); + HttpServer server = startServer(getBaseUri(), rc, getServerSslContext(), true); assertThat(server, instanceOf(HttpServer.class)); assertThat(server, not(instanceOf(HttpsServer.class))); } @@ -204,11 +201,7 @@ private SSLContext getServerSslContext() throws IOException { return sslConfigServer.createSSLContext(); } - @After - public void tearDown() { - if (server != null) { - server.stop(0); - server = null; - } + private URI getHttpsUri() { + return UriBuilder.fromUri("https://localhost/").port(getPort()).build(); } } diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java index dcfe4b7848..badb6ebba1 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java @@ -28,6 +28,7 @@ import org.glassfish.jersey.server.ResourceConfig; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.junit.After; /** @@ -50,20 +51,24 @@ public abstract class AbstractJettyServerTester { * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + } + final String value = AccessController .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -82,13 +87,13 @@ public void startServer(Class... resources) { config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); final URI baseUri = getBaseUri(); server = JettyHttpContainerFactory.createServer(baseUri, config); - LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); server = JettyHttpContainerFactory.createServer(baseUri, config); - LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + getBaseUri()); } public URI getBaseUri() { diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index 6f1a3a4d48..dd92a9b955 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -135,14 +135,14 @@ private static final int getPort() { if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value is not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (final NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index a34fbe2474..876db81fbe 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -137,14 +137,14 @@ private static final int getPort() { if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value is not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (final NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java index eb653ca4d8..3e4353e07b 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java @@ -49,21 +49,25 @@ public abstract class AbstractSimpleServerTester { * @return The HTTP port of the URI */ protected final int getPort() { + if (server != null) { + return server.getPort(); + } + final String value = AccessController .doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port")); if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (NumberFormatException e) { LOGGER.log( Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } @@ -83,28 +87,28 @@ public void startServer(Class... resources) { config.register(LoggingFeature.class); final URI baseUri = getBaseUri(); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServerNoLoggingFilter(Class... resources) { ResourceConfig config = new ResourceConfig(resources); final URI baseUri = getBaseUri(); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = SimpleContainerFactory.create(baseUri, config); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public void startServer(ResourceConfig config, int count, int select) { final URI baseUri = getBaseUri(); config.register(LoggingFeature.class); server = SimpleContainerFactory.create(baseUri, config, count, select); - LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri); + LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + getBaseUri()); } public URI getBaseUri() { diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index c2a98540c7..6d6e9af9e2 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -135,14 +135,14 @@ private static final int getPort() { if (value != null) { try { final int i = Integer.parseInt(value); - if (i <= 0) { - throw new NumberFormatException("Value is not positive."); + if (i < 0) { + throw new NumberFormatException("Value is negative."); } return i; } catch (final NumberFormatException e) { LOGGER.log(Level.CONFIG, "Value of 'jersey.config.test.container.port'" - + " property is not a valid positive integer [" + value + "]." + + " property is not a valid non-negative integer [" + value + "]." + " Reverting to default [" + DEFAULT_PORT + "].", e); } From f79bc007837762a274b8cd629a86460078db1539 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Mon, 27 Aug 2018 18:36:10 +0200 Subject: [PATCH 04/12] Tests do free port scan by default Signed-off-by: Markus KARG --- .../grizzly2/httpserver/GrizzlyHttpServerProviderTest.java | 2 +- .../glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/jetty/AbstractJettyServerTester.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/simple/AbstractSimpleServerTester.java | 2 +- .../glassfish/jersey/simple/SimpleHttpServerProviderTest.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index 9d08f16699..53ca699e2c 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -128,7 +128,7 @@ public final String toString() { private static final Logger LOGGER = Logger.getLogger(GrizzlyHttpServerProviderTest.class.getName()); - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; private static final int getPort() { final String value = AccessController diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java index 3c8f946354..b5c0be845a 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java @@ -38,7 +38,7 @@ public abstract class AbstractJdkHttpServerTester { public static final String CONTEXT = ""; - private final int DEFAULT_PORT = 9998; + private final int DEFAULT_PORT = 0; private static final Logger LOGGER = Logger.getLogger(AbstractJdkHttpServerTester.class.getName()); diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index f942a99537..e359367b38 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -129,7 +129,7 @@ public final String toString() { private static final Logger LOGGER = Logger.getLogger(JdkHttpServerProviderTest.class.getName()); - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; private static final int getPort() { final String value = AccessController diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java index badb6ebba1..d0bb6084c2 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java @@ -43,7 +43,7 @@ public abstract class AbstractJettyServerTester { private static final Logger LOGGER = Logger.getLogger(AbstractJettyServerTester.class.getName()); public static final String CONTEXT = ""; - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; /** * Get the port to be used for test application deployments. diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index dd92a9b955..9383b95acf 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -127,7 +127,7 @@ public final String toString() { private static final Logger LOGGER = Logger.getLogger(JettyHttpServerProviderTest.class.getName()); - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; private static final int getPort() { final String value = AccessController diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index 876db81fbe..5b0217e441 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -129,7 +129,7 @@ public final String toString() { } private static final Logger LOGGER = Logger.getLogger(NettyHttpServerProviderTest.class.getName()); - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; private static final int getPort() { final String value = AccessController diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java index 3e4353e07b..9ce80943da 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java @@ -39,7 +39,7 @@ public abstract class AbstractSimpleServerTester { public static final String CONTEXT = ""; - private final int DEFAULT_PORT = 9998; + private final int DEFAULT_PORT = 0; private static final Logger LOGGER = Logger.getLogger(AbstractSimpleServerTester.class.getName()); diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index 6d6e9af9e2..aefda17bee 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -127,7 +127,7 @@ public final String toString() { private static final Logger LOGGER = Logger.getLogger(SimpleHttpServerProviderTest.class.getName()); - private static final int DEFAULT_PORT = 9998; + private static final int DEFAULT_PORT = 0; private static final int getPort() { final String value = AccessController From 09dd82cd9e238232526cb7d7150ca6b2c0696221 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sat, 22 Sep 2018 14:38:30 +0200 Subject: [PATCH 05/12] Revert "Support for external configuration mechanics (Microprofile)" This reverts commit 0441f3a3d79f378e5f4369090cc4ef68aaf69001. Signed-off-by: Markus KARG --- bundles/jaxrs-ri/pom.xml | 6 -- core-server/pom.xml | 7 -- .../server/internal/RuntimeDelegateImpl.java | 14 ---- .../internal/RuntimeDelegateImplTest.java | 71 ------------------- pom.xml | 1 - 5 files changed, 99 deletions(-) diff --git a/bundles/jaxrs-ri/pom.xml b/bundles/jaxrs-ri/pom.xml index bec060ed21..ec7361b01f 100644 --- a/bundles/jaxrs-ri/pom.xml +++ b/bundles/jaxrs-ri/pom.xml @@ -190,12 +190,6 @@ jakarta.persistence-api provided - - org.eclipse.microprofile.config - microprofile-config-api - ${microprofile.config.version} - provided - diff --git a/core-server/pom.xml b/core-server/pom.xml index 64b7b5b770..282a12fef9 100644 --- a/core-server/pom.xml +++ b/core-server/pom.xml @@ -229,13 +229,6 @@ ${project.version} test - - - org.eclipse.microprofile.config - microprofile-config-api - ${microprofile.config.version} - provided - diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java index 9dba7c7ca1..82ab90bb49 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java @@ -35,7 +35,6 @@ import javax.ws.rs.JAXRS; import javax.ws.rs.JAXRS.Instance; -import org.eclipse.microprofile.config.Config; import org.glassfish.jersey.internal.AbstractRuntimeDelegate; import org.glassfish.jersey.message.internal.MessagingBinders; import org.glassfish.jersey.server.ContainerFactory; @@ -119,19 +118,6 @@ public final Builder from(final BiFunction, Optional> co return this; } - @Override - public final Builder from(final Object externalConfig) { - if (externalConfig instanceof Config) { - return this.from((Config) externalConfig); - } - - return this; - } - - private final Builder from(final Config config) { - return this.from(config::getOptionalValue); - } - @Override public final JAXRS.Configuration build() { return this.properties::get; diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java index f8b9076cf5..4f212a0687 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java @@ -41,8 +41,6 @@ import javax.ws.rs.core.Application; import javax.ws.rs.ext.RuntimeDelegate; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.spi.ConfigSource; import org.glassfish.jersey.internal.ServiceFinder; import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; import org.glassfish.jersey.server.ApplicationHandler; @@ -230,75 +228,6 @@ public final void shouldBuildCustomConfigurationFromPropertiesProvider() { assertThat(configuration.property(ServerProperties.AUTO_START), is(FALSE)); } - @Test - public final void shouldBuildCustomConfigurationFromMicroprofileConfig() { - // given - final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); - final SSLContext mockSslContext = new SSLContext(null, null, null) { - }; - final Class mockServerClass = Server.class; - final Config config = new Config() { - @Override - public final T getValue(final String propertyName, final Class propertyType) { - return null; - } - - @Override - public final Optional getOptionalValue(final String propertyName, final Class propertyType) { - if (JAXRS.Configuration.PROTOCOL.equals(propertyName) && String.class.equals(propertyType)) { - return Optional.of(propertyType.cast("HTTPS")); - } - if (JAXRS.Configuration.HOST.equals(propertyName) && String.class.equals(propertyType)) { - return Optional.of(propertyType.cast("hostname")); - } - if (JAXRS.Configuration.PORT.equals(propertyName) && Integer.class.equals(propertyType)) { - return Optional.of(propertyType.cast(8080)); - } - if (JAXRS.Configuration.ROOT_PATH.equals(propertyName) && String.class.equals(propertyType)) { - return Optional.of(propertyType.cast("path")); - } - if (JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION.equals(propertyName) - && JAXRS.Configuration.SSLClientAuthentication.class.equals(propertyType)) { - return Optional.of(propertyType.cast(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); - } - if (JAXRS.Configuration.SSL_CONTEXT.equals(propertyName) && SSLContext.class.equals(propertyType)) { - return Optional.of(propertyType.cast(mockSslContext)); - } - if (ServerProperties.HTTP_SERVER_CLASS.equals(propertyName) && Class.class.equals(propertyType)) { - return Optional.of(propertyType.cast(mockServerClass)); - } - if (ServerProperties.AUTO_START.equals(propertyName) && Boolean.class.equals(propertyType)) { - return Optional.of(propertyType.cast(FALSE)); - } - return Optional.empty(); - } - - @Override - public final Iterable getPropertyNames() { - return null; - } - - @Override - public final Iterable getConfigSources() { - return null; - } - }; - - // when - final JAXRS.Configuration configuration = configurationBuilder.from(config).build(); - - // then - assertThat(configuration, is(notNullValue())); - assertThat(configuration.protocol(), is("HTTPS")); - assertThat(configuration.host(), is("hostname")); - assertThat(configuration.port(), is(8080)); - assertThat(configuration.rootPath(), is("path")); - assertThat(configuration.sslClientAuthentication(), is(JAXRS.Configuration.SSLClientAuthentication.OPTIONAL)); - assertThat(configuration.sslContext(), is(theInstance(mockSslContext))); - assertThat(configuration.property(ServerProperties.HTTP_SERVER_CLASS), is(theInstance(mockServerClass))); - assertThat(configuration.property(ServerProperties.AUTO_START), is(FALSE)); - } - @Test public final void shouldBootstrapApplication() throws InterruptedException, ExecutionException, TimeoutException { // given diff --git a/pom.xml b/pom.xml index e184e20c40..8810f3b9a3 100644 --- a/pom.xml +++ b/pom.xml @@ -2041,6 +2041,5 @@ 2.11.0 1.0.3 false - 1.3 From 3f56b308c17886cc035b3951f40aeb5aa0e669d7 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 23 Sep 2018 16:55:27 +0200 Subject: [PATCH 06/12] Removed explicit duplicate JAX-RS version number Signed-off-by: Markus KARG --- core-server/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/core-server/pom.xml b/core-server/pom.xml index 282a12fef9..3069a25592 100644 --- a/core-server/pom.xml +++ b/core-server/pom.xml @@ -170,7 +170,6 @@ jakarta.ws.rs jakarta.ws.rs-api - 2.2-SNAPSHOT From 51957b687717b3828eb9d5817c59e54b1418526b Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 26 Aug 2018 17:49:07 +0200 Subject: [PATCH 07/12] Support for JAXRS.Configuration.FREE_PORT Signed-off-by: Markus KARG --- .../grizzly2/httpserver/GrizzlyHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProviderTest.java | 2 +- .../glassfish/jersey/simple/SimpleHttpServerProviderTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index 53ca699e2c..e08ea83146 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -164,7 +164,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc case JAXRS.Configuration.HOST: return "localhost"; case JAXRS.Configuration.PORT: - return 0; + return JAXRS.Configuration.FREE_PORT; case JAXRS.Configuration.ROOT_PATH: return "/"; case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index e359367b38..ad15cf6468 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -165,7 +165,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc case JAXRS.Configuration.HOST: return "localhost"; case JAXRS.Configuration.PORT: - return 0; + return JAXRS.Configuration.FREE_PORT; case JAXRS.Configuration.ROOT_PATH: return "/"; case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index 9383b95acf..6479b6440b 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -163,7 +163,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc case JAXRS.Configuration.HOST: return "localhost"; case JAXRS.Configuration.PORT: - return 0; + return JAXRS.Configuration.FREE_PORT; case JAXRS.Configuration.ROOT_PATH: return "/"; case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index 5b0217e441..668ee9da98 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -165,7 +165,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc case JAXRS.Configuration.HOST: return "localhost"; case JAXRS.Configuration.PORT: - return 0; + return JAXRS.Configuration.FREE_PORT; case JAXRS.Configuration.ROOT_PATH: return "/"; case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index aefda17bee..4a25f00385 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -163,7 +163,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc case JAXRS.Configuration.HOST: return "localhost"; case JAXRS.Configuration.PORT: - return 0; + return JAXRS.Configuration.FREE_PORT; case JAXRS.Configuration.ROOT_PATH: return "/"; case JAXRS.Configuration.SSL_CLIENT_AUTHENTICATION: From e14c903adc05acb7d80b6a1b751507963dc6b1d8 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Tue, 25 Sep 2018 07:13:46 +0200 Subject: [PATCH 08/12] Using hamcrest-library instead of hamcrest-junit Signed-off-by: Markus KARG --- containers/grizzly2-http/pom.xml | 4 +--- containers/jdk-http/pom.xml | 4 +--- containers/jetty-http/pom.xml | 4 +--- containers/netty-http/pom.xml | 4 +--- containers/simple-http/pom.xml | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/containers/grizzly2-http/pom.xml b/containers/grizzly2-http/pom.xml index 47589b87e5..8ca8823727 100644 --- a/containers/grizzly2-http/pom.xml +++ b/containers/grizzly2-http/pom.xml @@ -43,9 +43,7 @@ org.hamcrest - hamcrest-junit - 2.0.0.0 - test + hamcrest-library diff --git a/containers/jdk-http/pom.xml b/containers/jdk-http/pom.xml index d1ffc9675b..6601b6f9c7 100644 --- a/containers/jdk-http/pom.xml +++ b/containers/jdk-http/pom.xml @@ -40,9 +40,7 @@ org.hamcrest - hamcrest-junit - 2.0.0.0 - test + hamcrest-library diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml index 973f2389c7..0787c91adc 100644 --- a/containers/jetty-http/pom.xml +++ b/containers/jetty-http/pom.xml @@ -52,9 +52,7 @@ org.hamcrest - hamcrest-junit - 2.0.0.0 - test + hamcrest-library diff --git a/containers/netty-http/pom.xml b/containers/netty-http/pom.xml index 8fb7b4e893..e8deb20501 100644 --- a/containers/netty-http/pom.xml +++ b/containers/netty-http/pom.xml @@ -44,9 +44,7 @@ org.hamcrest - hamcrest-junit - 2.0.0.0 - test + hamcrest-library diff --git a/containers/simple-http/pom.xml b/containers/simple-http/pom.xml index 0a08a01e6b..b7c6f73d13 100644 --- a/containers/simple-http/pom.xml +++ b/containers/simple-http/pom.xml @@ -51,9 +51,7 @@ org.hamcrest - hamcrest-junit - 2.0.0.0 - test + hamcrest-library From ce5d16685ad6668a3460b99e67725f9862ae485e Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sun, 17 Feb 2019 17:04:33 +0100 Subject: [PATCH 09/12] Fixed failing tests Signed-off-by: Markus KARG --- .../jersey/server/ServerFactoryTest.java | 133 ++++++++++++++++-- .../internal/RuntimeDelegateImplTest.java | 8 ++ 2 files changed, 129 insertions(+), 12 deletions(-) diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java index 362d001186..08949e7354 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java @@ -20,8 +20,10 @@ import static org.hamcrest.CoreMatchers.theInstance; import static org.junit.Assert.assertThat; -import java.util.Collections; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.util.Iterator; +import java.util.List; import java.util.concurrent.CompletionStage; import javax.ws.rs.JAXRS; @@ -30,9 +32,17 @@ import org.glassfish.jersey.internal.ServiceFinder; import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; +import org.glassfish.jersey.internal.guava.Iterators; +import org.glassfish.jersey.internal.inject.Binder; +import org.glassfish.jersey.internal.inject.Binding; +import org.glassfish.jersey.internal.inject.ForeignDescriptor; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManagerFactory; +import org.glassfish.jersey.internal.inject.ServiceHolder; import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.Server; import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.After; import org.junit.Test; /** @@ -76,20 +86,114 @@ public final T unwrap(final Class nativeClass) { } }; ServiceFinder.setIteratorProvider(new ServiceIteratorProvider() { - @Override public final Iterator createIterator(final Class service, final String serviceName, final ClassLoader loader, final boolean ignoreOnClassNotFound) { - return Collections.singleton(service.cast(new ServerProvider() { - - @Override - public final U createServer(final Class type, final Application application, - final Configuration configuration) { - return application == mockApplication && configuration == mockConfiguration - ? type.cast(mockServer) - : null; - } - })).iterator(); + return Iterators.singletonIterator(service.cast( + service == ServerProvider.class ? new ServerProvider() { + @Override + public final U createServer(final Class type, final Application application, + final Configuration configuration) { + return application == mockApplication && configuration == mockConfiguration + ? type.cast(mockServer) + : null; + } + } + : service == InjectionManagerFactory.class ? new InjectionManagerFactory() { + @Override + public final InjectionManager create(final Object parent) { + return new InjectionManager() { + + @Override + public void completeRegistration() { + } + + @Override + public void shutdown() { + } + + @Override + public void register(Binding binding) { + } + + @Override + public void register(Iterable descriptors) { + } + + @Override + public void register(Binder binder) { + } + + @Override + public void register(Object provider) throws IllegalArgumentException { + } + + @Override + public boolean isRegistrable(Class clazz) { + return false; + } + + @Override + public T createAndInitialize(Class createMe) { + return null; + } + + @Override + public List> getAllServiceHolders(Class contractOrImpl, + Annotation... qualifiers) { + return null; + } + + @Override + public T getInstance(Class contractOrImpl, Annotation... qualifiers) { + return null; + } + + @Override + public T getInstance(Class contractOrImpl, String classAnalyzer) { + return null; + } + + @Override + public T getInstance(Class contractOrImpl) { + return null; + } + + @Override + public T getInstance(Type contractOrImpl) { + return null; + } + + @Override + public Object getInstance(ForeignDescriptor foreignDescriptor) { + return null; + } + + @Override + public ForeignDescriptor createForeignDescriptor(Binding binding) { + return null; + } + + @Override + public List getAllInstances(Type contractOrImpl) { + return null; + } + + @Override + public void inject(Object injectMe) { + } + + @Override + public void inject(Object injectMe, String classAnalyzer) { + } + + @Override + public void preDestroy(Object preDestroyMe) { + } + }; + } + } + : null)); } @Override @@ -106,4 +210,9 @@ public final Iterator> createClassIterator(final Class service, assertThat(server, is(theInstance(mockServer))); } + @After + public final void resetServiceFinder() { + ServiceFinder.setIteratorProvider(null); + } + } diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java index 4f212a0687..5be475298e 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java @@ -25,6 +25,8 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Iterator; @@ -49,6 +51,7 @@ import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.Server; import org.glassfish.jersey.server.spi.ServerProvider; +import org.junit.After; import org.junit.Test; /** @@ -347,4 +350,9 @@ public final Iterator> createClassIterator(final Class service, assertThat(stopResult, is(notNullValue())); } + @After + public final void resetServiceFinder() { + ServiceFinder.setIteratorProvider(null); + } + } From e331ce861ebf67e8d0e53cd2fa925c3323db09c3 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Sat, 16 Feb 2019 22:57:05 +0100 Subject: [PATCH 10/12] Using JMockit instead of custom mocks Signed-off-by: Markus KARG --- .../jersey/server/ServerFactoryTest.java | 136 ++---------------- .../internal/RuntimeDelegateImplTest.java | 49 ++----- 2 files changed, 21 insertions(+), 164 deletions(-) diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java index 08949e7354..d81984aab8 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java @@ -20,11 +20,7 @@ import static org.hamcrest.CoreMatchers.theInstance; import static org.junit.Assert.assertThat; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CompletionStage; import javax.ws.rs.JAXRS; import javax.ws.rs.JAXRS.Configuration; @@ -33,17 +29,16 @@ import org.glassfish.jersey.internal.ServiceFinder; import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; import org.glassfish.jersey.internal.guava.Iterators; -import org.glassfish.jersey.internal.inject.Binder; -import org.glassfish.jersey.internal.inject.Binding; -import org.glassfish.jersey.internal.inject.ForeignDescriptor; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.internal.inject.InjectionManagerFactory; -import org.glassfish.jersey.internal.inject.ServiceHolder; -import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.Server; import org.glassfish.jersey.server.spi.ServerProvider; import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; + +import mockit.Mocked; +import mockit.integration.junit4.JMockit; /** * Unit tests for {@link ServerFactory}. @@ -51,40 +46,13 @@ * @author Markus KARG (markus@headcrashing.eu) * @since 2.28 */ +@RunWith(JMockit.class) public final class ServerFactoryTest { @Test - public final void shouldBuildServer() { + public final void shouldBuildServer(@Mocked final Application mockApplication, @Mocked final Server mockServer, + @Mocked final JAXRS.Configuration mockConfiguration, @Mocked final InjectionManager mockInjectionManager) { // given - final Application mockApplication = new Application(); - final JAXRS.Configuration mockConfiguration = name -> null; - final Server mockServer = new Server() { - - @Override - public final Container container() { - return null; - } - - @Override - public final int port() { - return 0; - } - - @Override - public final CompletionStage start() { - return null; - } - - @Override - public final CompletionStage stop() { - return null; - } - - @Override - public final T unwrap(final Class nativeClass) { - return null; - } - }; ServiceFinder.setIteratorProvider(new ServiceIteratorProvider() { @Override public final Iterator createIterator(final Class service, final String serviceName, @@ -102,95 +70,7 @@ public final U createServer(final Class type, final Applic : service == InjectionManagerFactory.class ? new InjectionManagerFactory() { @Override public final InjectionManager create(final Object parent) { - return new InjectionManager() { - - @Override - public void completeRegistration() { - } - - @Override - public void shutdown() { - } - - @Override - public void register(Binding binding) { - } - - @Override - public void register(Iterable descriptors) { - } - - @Override - public void register(Binder binder) { - } - - @Override - public void register(Object provider) throws IllegalArgumentException { - } - - @Override - public boolean isRegistrable(Class clazz) { - return false; - } - - @Override - public T createAndInitialize(Class createMe) { - return null; - } - - @Override - public List> getAllServiceHolders(Class contractOrImpl, - Annotation... qualifiers) { - return null; - } - - @Override - public T getInstance(Class contractOrImpl, Annotation... qualifiers) { - return null; - } - - @Override - public T getInstance(Class contractOrImpl, String classAnalyzer) { - return null; - } - - @Override - public T getInstance(Class contractOrImpl) { - return null; - } - - @Override - public T getInstance(Type contractOrImpl) { - return null; - } - - @Override - public Object getInstance(ForeignDescriptor foreignDescriptor) { - return null; - } - - @Override - public ForeignDescriptor createForeignDescriptor(Binding binding) { - return null; - } - - @Override - public List getAllInstances(Type contractOrImpl) { - return null; - } - - @Override - public void inject(Object injectMe) { - } - - @Override - public void inject(Object injectMe, String classAnalyzer) { - } - - @Override - public void preDestroy(Object preDestroyMe) { - } - }; + return mockInjectionManager; } } : null)); diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java index 5be475298e..2af3eb29d1 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/RuntimeDelegateImplTest.java @@ -25,8 +25,6 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Iterator; @@ -45,14 +43,16 @@ import org.glassfish.jersey.internal.ServiceFinder; import org.glassfish.jersey.internal.ServiceFinder.ServiceIteratorProvider; -import org.glassfish.jersey.server.ApplicationHandler; -import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.Server; import org.glassfish.jersey.server.spi.ServerProvider; import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; + +import mockit.Mocked; +import mockit.integration.junit4.JMockit; /** * Unit tests for {@link RuntimeDelegate}. @@ -60,6 +60,7 @@ * @author Martin Matula * @author Markus KARG (markus@headcrashing.eu) */ +@RunWith(JMockit.class) public class RuntimeDelegateImplTest { @Test @@ -134,11 +135,10 @@ public final void shouldBuildConfigurationContainingCustomProperties() { } @Test - public final void shouldBuildCustomConfigurationUsingNamedStandardProperties() throws NoSuchAlgorithmException { + public final void shouldBuildCustomConfigurationUsingNamedStandardProperties(@Mocked final SSLContext mockSslContext) + throws NoSuchAlgorithmException { // given final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); - final SSLContext mockSslContext = new SSLContext(null, null, null) { - }; // when final JAXRS.Configuration configuration = configurationBuilder.property(JAXRS.Configuration.PROTOCOL, "HTTPS") @@ -159,11 +159,10 @@ public final void shouldBuildCustomConfigurationUsingNamedStandardProperties() t } @Test - public final void shouldBuildCustomConfigurationUsingConvenienceMethods() throws NoSuchAlgorithmException { + public final void shouldBuildCustomConfigurationUsingConvenienceMethods(@Mocked final SSLContext mockSslContext) + throws NoSuchAlgorithmException { // given final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); - final SSLContext mockSslContext = new SSLContext(null, null, null) { - }; // when final JAXRS.Configuration configuration = configurationBuilder.protocol("HTTPS").host("hostname").port(8080) @@ -181,11 +180,9 @@ public final void shouldBuildCustomConfigurationUsingConvenienceMethods() throws } @Test - public final void shouldBuildCustomConfigurationFromPropertiesProvider() { + public final void shouldBuildCustomConfigurationFromPropertiesProvider(@Mocked final SSLContext mockSslContext) { // given final JAXRS.Configuration.Builder configurationBuilder = new RuntimeDelegateImpl().createConfigurationBuilder(); - final SSLContext mockSslContext = new SSLContext(null, null, null) { - }; final Class mockServerClass = Server.class; final BiFunction, Optional> propertiesProvider = (propertyName, propertyType) -> { if (JAXRS.Configuration.PROTOCOL.equals(propertyName) && String.class.equals(propertyType)) { @@ -232,27 +229,10 @@ public final void shouldBuildCustomConfigurationFromPropertiesProvider() { } @Test - public final void shouldBootstrapApplication() throws InterruptedException, ExecutionException, TimeoutException { + public final void shouldBootstrapApplication(@Mocked final Container mockContainer, + @Mocked final Application mockApplication, @Mocked final SSLContext mockSslContext) throws InterruptedException, + ExecutionException, TimeoutException { // given - final Container mockContainer = new Container() { - @Override - public final ResourceConfig getConfiguration() { - return null; - } - - @Override - public final ApplicationHandler getApplicationHandler() { - return null; - } - - @Override - public final void reload() { - } - - @Override - public final void reload(final ResourceConfig configuration) { - } - }; final Server mockServer = new Server() { @Override public final Container container() { @@ -280,9 +260,6 @@ public final T unwrap(final Class nativeClass) { } }; final RuntimeDelegate runtimeDelegate = new RuntimeDelegateImpl(); - final Application mockApplication = new Application(); - final SSLContext mockSslContext = new SSLContext(null, null, null) { - }; final JAXRS.Configuration mockConfiguration = name -> { switch (name) { case JAXRS.Configuration.PROTOCOL: From 02629aa3e2a0634f25271b522a9a5e416ca59d66 Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Wed, 20 Feb 2019 07:01:55 +0100 Subject: [PATCH 11/12] @since 2.29 Signed-off-by: Markus KARG --- .../glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java | 2 +- .../jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java | 2 +- .../grizzly2/httpserver/GrizzlyHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/jetty/JettyHttpServer.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProvider.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/netty/httpserver/NettyHttpServer.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProvider.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/simple/SimpleHttpServer.java | 2 +- .../org/glassfish/jersey/simple/SimpleHttpServerProvider.java | 2 +- .../glassfish/jersey/simple/SimpleHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/server/ServerFactory.java | 2 +- .../src/main/java/org/glassfish/jersey/server/spi/Server.java | 2 +- .../java/org/glassfish/jersey/server/spi/ServerProvider.java | 2 +- .../java/org/glassfish/jersey/server/ServerFactoryTest.java | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java index a08eccdb90..5d2c23cb4c 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java @@ -40,7 +40,7 @@ * Jersey {@code Server} implementation based on Grizzly {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class GrizzlyHttpServer implements Server { diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java index 35926cf750..5b061caa36 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java @@ -27,7 +27,7 @@ * Server provider for servers based on Grizzly {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class GrizzlyHttpServerProvider implements ServerProvider { diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index e08ea83146..3580f3edbd 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -54,7 +54,7 @@ * Unit tests for {@link GrizzlyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class GrizzlyHttpServerProviderTest { diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java index b23941f858..fd95ea2abb 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java @@ -38,7 +38,7 @@ * Jersey {@code Server} implementation based on JDK {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JdkHttpServer implements Server { diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java index 9a6572090e..91f6c1cd51 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java @@ -28,7 +28,7 @@ * Server provider for servers based on JDK {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JdkHttpServerProvider implements ServerProvider { diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index ad15cf6468..a4e2556952 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -55,7 +55,7 @@ * Unit tests for {@link JdkHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JdkHttpServerProviderTest { diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java index 492452108b..ccee65f858 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java @@ -41,7 +41,7 @@ * {@link org.eclipse.jetty.server.Server Server}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JettyHttpServer implements Server { diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java index afeb9c7a20..2e67193833 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java @@ -27,7 +27,7 @@ * {@link org.eclipse.jetty.server.Server Server}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JettyHttpServerProvider implements ServerProvider { diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index 6479b6440b..39e896aa13 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -53,7 +53,7 @@ * Unit tests for {@link JettyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class JettyHttpServerProviderTest { diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java index 72e66d4549..9ed174fe8c 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java @@ -41,7 +41,7 @@ * Jersey {@code Server} implementation based on Netty {@link Channel}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class NettyHttpServer implements Server { diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java index 4376a3af9f..ee0a4910f7 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java @@ -28,7 +28,7 @@ * Server provider for servers based on Netty {@link Channel}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class NettyHttpServerProvider implements ServerProvider { diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index 668ee9da98..6f20dca675 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -56,7 +56,7 @@ * Unit tests for {@link NettyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class NettyHttpServerProviderTest { diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java index bffed80cff..f51997b8b4 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java @@ -36,7 +36,7 @@ * {@link SimpleServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class SimpleHttpServer implements Server { diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java index 9b431bb21e..c14bd20cae 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java @@ -26,7 +26,7 @@ * Server provider for servers based on Simple framework {@link SimpleServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class SimpleHttpServerProvider implements ServerProvider { diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index 4a25f00385..b74f956cc4 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -53,7 +53,7 @@ * Unit tests for {@link SimpleHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class SimpleHttpServerProviderTest { diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java index 03e286a641..2c657d22c3 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java @@ -28,7 +28,7 @@ * Factory for creating specific HTTP servers. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ public final class ServerFactory { diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java index 07a1724b94..a235b39f7e 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java @@ -32,7 +32,7 @@ *

* * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ @Contract @ConstrainedTo(RuntimeType.SERVER) diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java index 8455e87523..d8eb02a90b 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java @@ -58,7 +58,7 @@ *

* * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ @Contract @ConstrainedTo(RuntimeType.SERVER) diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java index d81984aab8..64d2ffe7f8 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java @@ -44,7 +44,7 @@ * Unit tests for {@link ServerFactory}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.28 + * @since 2.29 */ @RunWith(JMockit.class) public final class ServerFactoryTest { From c6a3794bb5be04250f0df6eb9940de3cf105e20f Mon Sep 17 00:00:00 2001 From: Markus KARG Date: Thu, 28 Mar 2019 19:35:34 +0100 Subject: [PATCH 12/12] @since 2.30 Signed-off-by: Markus KARG --- .../glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java | 2 +- .../jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java | 2 +- .../grizzly2/httpserver/GrizzlyHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java | 2 +- .../org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/jetty/JettyHttpServer.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProvider.java | 2 +- .../org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java | 2 +- .../org/glassfish/jersey/netty/httpserver/NettyHttpServer.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProvider.java | 2 +- .../jersey/netty/httpserver/NettyHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/simple/SimpleHttpServer.java | 2 +- .../org/glassfish/jersey/simple/SimpleHttpServerProvider.java | 2 +- .../glassfish/jersey/simple/SimpleHttpServerProviderTest.java | 2 +- .../main/java/org/glassfish/jersey/server/ServerFactory.java | 2 +- .../src/main/java/org/glassfish/jersey/server/spi/Server.java | 2 +- .../java/org/glassfish/jersey/server/spi/ServerProvider.java | 2 +- .../java/org/glassfish/jersey/server/ServerFactoryTest.java | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java index 5d2c23cb4c..581b7eed55 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServer.java @@ -40,7 +40,7 @@ * Jersey {@code Server} implementation based on Grizzly {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class GrizzlyHttpServer implements Server { diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java index 5b061caa36..82a99ee263 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProvider.java @@ -27,7 +27,7 @@ * Server provider for servers based on Grizzly {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class GrizzlyHttpServerProvider implements ServerProvider { diff --git a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java index 3580f3edbd..647d6d1246 100644 --- a/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java +++ b/containers/grizzly2-http/src/test/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerProviderTest.java @@ -54,7 +54,7 @@ * Unit tests for {@link GrizzlyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class GrizzlyHttpServerProviderTest { diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java index fd95ea2abb..16a445c5aa 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServer.java @@ -38,7 +38,7 @@ * Jersey {@code Server} implementation based on JDK {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JdkHttpServer implements Server { diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java index 91f6c1cd51..6c10cab952 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProvider.java @@ -28,7 +28,7 @@ * Server provider for servers based on JDK {@link HttpServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JdkHttpServerProvider implements ServerProvider { diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java index a4e2556952..c7c4e444b7 100644 --- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java +++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpServerProviderTest.java @@ -55,7 +55,7 @@ * Unit tests for {@link JdkHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JdkHttpServerProviderTest { diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java index ccee65f858..bb223434fe 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServer.java @@ -41,7 +41,7 @@ * {@link org.eclipse.jetty.server.Server Server}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JettyHttpServer implements Server { diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java index 2e67193833..8dc3fe3df2 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpServerProvider.java @@ -27,7 +27,7 @@ * {@link org.eclipse.jetty.server.Server Server}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JettyHttpServerProvider implements ServerProvider { diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java index 39e896aa13..c4dc31ee45 100644 --- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java +++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/JettyHttpServerProviderTest.java @@ -53,7 +53,7 @@ * Unit tests for {@link JettyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class JettyHttpServerProviderTest { diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java index 9ed174fe8c..ee45da37b5 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServer.java @@ -41,7 +41,7 @@ * Jersey {@code Server} implementation based on Netty {@link Channel}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class NettyHttpServer implements Server { diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java index ee0a4910f7..7238988272 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProvider.java @@ -28,7 +28,7 @@ * Server provider for servers based on Netty {@link Channel}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class NettyHttpServerProvider implements ServerProvider { diff --git a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java index 6f20dca675..951ad28cc7 100644 --- a/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java +++ b/containers/netty-http/src/test/java/org/glassfish/jersey/netty/httpserver/NettyHttpServerProviderTest.java @@ -56,7 +56,7 @@ * Unit tests for {@link NettyHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class NettyHttpServerProviderTest { diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java index f51997b8b4..4176fbb637 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServer.java @@ -36,7 +36,7 @@ * {@link SimpleServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class SimpleHttpServer implements Server { diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java index c14bd20cae..70b40b965d 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleHttpServerProvider.java @@ -26,7 +26,7 @@ * Server provider for servers based on Simple framework {@link SimpleServer}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class SimpleHttpServerProvider implements ServerProvider { diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java index b74f956cc4..fe483a01f8 100644 --- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java +++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/SimpleHttpServerProviderTest.java @@ -53,7 +53,7 @@ * Unit tests for {@link SimpleHttpServerProvider}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class SimpleHttpServerProviderTest { diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java index 2c657d22c3..9bd4656580 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerFactory.java @@ -28,7 +28,7 @@ * Factory for creating specific HTTP servers. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ public final class ServerFactory { diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java index a235b39f7e..71d9750f50 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/Server.java @@ -32,7 +32,7 @@ *

* * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ @Contract @ConstrainedTo(RuntimeType.SERVER) diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java index d8eb02a90b..f0dd87df04 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/ServerProvider.java @@ -58,7 +58,7 @@ *

* * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ @Contract @ConstrainedTo(RuntimeType.SERVER) diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java index 64d2ffe7f8..90333181fe 100644 --- a/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java +++ b/core-server/src/test/java/org/glassfish/jersey/server/ServerFactoryTest.java @@ -44,7 +44,7 @@ * Unit tests for {@link ServerFactory}. * * @author Markus KARG (markus@headcrashing.eu) - * @since 2.29 + * @since 2.30 */ @RunWith(JMockit.class) public final class ServerFactoryTest {