diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java index 686f50fa2e..616ea14249 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021 Oracle and/or its affiliates. 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 @@ -307,9 +307,16 @@ private void rethrow(final Throwable error) { * @param application JAX-RS / Jersey application to be deployed on Grizzly HTTP container. */ /* package */ GrizzlyHttpContainer(final Application application) { - this.appHandler = new ApplicationHandler(application, new GrizzlyBinder()); - cacheConfigSetStatusOverSendError(); - cacheConfigEnableLeadingContextPathSlashes(); + this(new ApplicationHandler(application, new GrizzlyBinder())); + } + + /** + * Create a new Grizzly HTTP container. + * + * @param applicationClass JAX-RS / Jersey application to be deployed on Grizzly HTTP container. + */ + /* package */ GrizzlyHttpContainer(final Class applicationClass) { + this(new ApplicationHandler(applicationClass, new GrizzlyBinder())); } /** @@ -319,7 +326,11 @@ private void rethrow(final Throwable error) { * @param parentContext DI provider specific context with application's registered bindings. */ /* package */ GrizzlyHttpContainer(final Application application, final Object parentContext) { - this.appHandler = new ApplicationHandler(application, new GrizzlyBinder(), parentContext); + this(new ApplicationHandler(application, new GrizzlyBinder(), parentContext)); + } + + private GrizzlyHttpContainer(ApplicationHandler applicationHandler) { + this.appHandler = applicationHandler; cacheConfigSetStatusOverSendError(); cacheConfigEnableLeadingContextPathSlashes(); } 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 8e2dcbbd12..c3463dce13 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 @@ -46,11 +46,20 @@ final class GrizzlyHttpServer implements WebServer { private final HttpServer httpServer; GrizzlyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new GrizzlyHttpContainer(application), configuration); + } + + GrizzlyHttpServer(final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new GrizzlyHttpContainer(applicationClass), configuration); + } + + private GrizzlyHttpServer(final GrizzlyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { final SSLContext sslContext = configuration.sslContext(); final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration .sslClientAuthentication(); - this.container = new GrizzlyHttpContainer(application); + this.container = container; this.httpServer = GrizzlyHttpServerFactory.createHttpServer( configuration.uri(false), this.container, 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 b6f1bf238b..a3f911c61f 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 @@ -39,4 +39,12 @@ public final T createServer(final Class type, final App ? type.cast(new GrizzlyHttpServer(application, configuration)) : null; } + + @Override + public T createServer(Class type, Class applicationClass, + JerseySeBootstrapConfiguration configuration) { + return GrizzlyHttpServer.class == type || WebServer.class == type + ? type.cast(new GrizzlyHttpServer(applicationClass, configuration)) + : null; + } } 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 6bf054cae7..a7310d048d 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 @@ -61,44 +61,31 @@ public final class GrizzlyHttpServerProviderTest { @Test(timeout = 15000) - public final void shouldProvideServer() throws InterruptedException, ExecutionException { + public void shouldProvideServer() throws InterruptedException, ExecutionException { // given - final WebServerProvider webServerProvider = new GrizzlyHttpServerProvider(); final Resource resource = new Resource(); - final Application application = new Application() { - @Override - public final Set getSingletons() { - return Collections.singleton(resource); - } - }; - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return getPort(); - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return FALSE; - default: - return null; - } - }; + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test(timeout = 15000) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new GrizzlyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort()); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); - final WebServer webServer = webServerProvider.createServer(WebServer.class, application, jerseySeConfig); + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, jerseySeConfig) + : webServerProvider.createServer(WebServer.class, (Class) application, jerseySeConfig); final Object nativeHandle = webServer.unwrap(Object.class); final CompletionStage start = webServer.start(); final Object startResult = start.toCompletableFuture().get(); @@ -124,8 +111,15 @@ public final Set getSingletons() { protected static final class Resource { @GET @Override - public final String toString() { - return super.toString(); + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public final Set getSingletons() { + return Collections.singleton(new Resource()); } } @@ -156,35 +150,11 @@ private static final int getPort() { } @Test(timeout = 15000) - public final void shouldScanFreePort() throws InterruptedException, ExecutionException { + public void shouldScanFreePort() { // given final WebServerProvider webServerProvider = new GrizzlyHttpServerProvider(); final Application application = new Application(); - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return SeBootstrap.Configuration.FREE_PORT; - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return TRUE; - default: - return null; - } - }; - + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); @@ -194,4 +164,31 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc assertThat(webServer.port(), is(greaterThan(0))); } + private SeBootstrap.Configuration configuration(int port) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return TRUE; + default: + return null; + } + }; + } + } diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java index 89f47d24d2..5acf6a10e7 100644 --- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java +++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021 Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ public class JdkHttpHandlerContainer implements HttpHandler, Container { private volatile ApplicationHandler appHandler; /** - * Create new lightweight Java SE HTTP server container. + * Create new lightweight Java SE HTTP server container. * * @param application JAX-RS / Jersey application to be deployed on the container. */ @@ -73,7 +73,16 @@ public class JdkHttpHandlerContainer implements HttpHandler, Container { } /** - * Create new lightweight Java SE HTTP server container. + * Create new lightweight Java SE HTTP server container. + * + * @param applicationClass class of JAX-RS / Jersey application to be deployed on the container. + */ + JdkHttpHandlerContainer(final Class applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass); + } + + /** + * Create new lightweight Java SE HTTP server container. * * @param application JAX-RS / Jersey application to be deployed on the container. * @param parentContext DI provider specific context with application's registered bindings. 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 b283ba2413..d53a75808a 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 @@ -43,10 +43,19 @@ final class JdkHttpServer implements WebServer { private final HttpServer httpServer; JdkHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new JdkHttpHandlerContainer(application), configuration); + } + + JdkHttpServer(final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JdkHttpHandlerContainer(applicationClass), configuration); + } + + JdkHttpServer(final JdkHttpHandlerContainer container, final JerseySeBootstrapConfiguration configuration) { final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration .sslClientAuthentication(); - this.container = new JdkHttpHandlerContainer(application); + this.container = container; this.httpServer = JdkHttpServerFactory.createHttpServer( configuration.uri(false), this.container, 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 e40bc2d175..4510c53fc8 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 @@ -34,10 +34,18 @@ public final class JdkHttpServerProvider implements WebServerProvider { @Override - public final T createServer(final Class type, final Application application, + public T createServer(final Class type, final Application application, final JerseySeBootstrapConfiguration configuration) { return JdkHttpServer.class == type || WebServer.class == type ? type.cast(new JdkHttpServer(application, configuration)) : null; } + + @Override + public T createServer(final Class type, final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + return JdkHttpServer.class == type || WebServer.class == type + ? type.cast(new JdkHttpServer(applicationClass, configuration)) + : null; + } } 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 567b5b3a6d..ade52847c5 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 @@ -62,44 +62,31 @@ public final class JdkHttpServerProviderTest { @Test(timeout = 15000) - public final void shouldProvideServer() throws InterruptedException, ExecutionException { + public void shouldProvideServer() throws InterruptedException, ExecutionException { // given - final WebServerProvider webServerProvider = new JdkHttpServerProvider(); final Resource resource = new Resource(); - final Application application = new Application() { - @Override - public final Set getSingletons() { - return Collections.singleton(resource); - } - }; - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return getPort(); - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return FALSE; - default: - return null; - } - }; + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test(timeout = 15000) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JdkHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort()); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); - final WebServer webServer = webServerProvider.createServer(WebServer.class, application, jerseySeConfig); + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, jerseySeConfig) + : webServerProvider.createServer(WebServer.class, (Class) application, jerseySeConfig); final Object nativeHandle = webServer.unwrap(Object.class); final CompletionStage start = webServer.start(); final Object startResult = start.toCompletableFuture().get(); @@ -125,8 +112,15 @@ public final Set getSingletons() { protected static final class Resource { @GET @Override - public final String toString() { - return super.toString(); + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set getSingletons() { + return Collections.singleton(new Resource()); } } @@ -161,30 +155,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc // given final WebServerProvider webServerProvider = new JdkHttpServerProvider(); final Application application = new Application(); - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return SeBootstrap.Configuration.FREE_PORT; - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return TRUE; - default: - return null; - } - }; + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); @@ -194,4 +165,30 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc assertThat(webServer.port(), is(greaterThan(0))); } + private SeBootstrap.Configuration configuration(int port) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return FALSE; + default: + return null; + } + }; + } } diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java index 26ccd92d11..ec14d86068 100644 --- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java +++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java @@ -491,6 +491,17 @@ public void doStop() throws Exception { cacheConfigSetStatusOverSendError(); } + /** + * Create a new Jetty HTTP container. + * + * @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container. + */ + JettyHttpContainer(final Class applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass, new JettyBinder()); + + cacheConfigSetStatusOverSendError(); + } + /** * The method reads and caches value of configuration property * {@link ServerProperties#RESPONSE_SET_STATUS_OVER_SEND_ERROR} for future purposes. 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 836ddd6d51..9f014f4f14 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 @@ -46,6 +46,15 @@ final class JettyHttpServer implements WebServer { private final org.eclipse.jetty.server.Server httpServer; JettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(ContainerFactory.createContainer(JettyHttpContainer.class, application), configuration); + } + + JettyHttpServer(final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new JettyHttpContainer(applicationClass), configuration); + } + + JettyHttpServer(final JettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration .sslClientAuthentication(); final SslContextFactory.Server sslContextFactory; @@ -57,7 +66,7 @@ final class JettyHttpServer implements WebServer { } else { sslContextFactory = null; } - this.container = ContainerFactory.createContainer(JettyHttpContainer.class, application); + this.container = container; this.httpServer = JettyHttpContainerFactory.createServer( configuration.uri(false), sslContextFactory, 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 8d1a1ef6e6..fe776b9f40 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 @@ -39,4 +39,12 @@ public final T createServer(final Class type, final App ? type.cast(new JettyHttpServer(application, configuration)) : null; } + + @Override + public T createServer(final Class type, final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + return JettyHttpServer.class == type || WebServer.class == type + ? type.cast(new JettyHttpServer(applicationClass, configuration)) + : null; + } } 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 c7efc7e102..1aa8b45495 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 @@ -35,6 +35,7 @@ import java.util.logging.Logger; import javax.net.ssl.SSLContext; + import jakarta.ws.rs.GET; import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.SeBootstrap.Configuration.SSLClientAuthentication; @@ -60,44 +61,31 @@ public final class JettyHttpServerProviderTest { @Test(timeout = 15000) - public final void shouldProvideServer() throws InterruptedException, ExecutionException { + public void shouldProvideServer() throws InterruptedException, ExecutionException { // given - final WebServerProvider webServerProvider = new JettyHttpServerProvider(); final Resource resource = new Resource(); - final Application application = new Application() { - @Override - public final Set getSingletons() { - return Collections.singleton(resource); - } - }; - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return getPort(); - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return FALSE; - default: - return null; - } - }; + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test(timeout = 15000) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new JettyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); - final WebServer webServer = webServerProvider.createServer(WebServer.class, application, jerseySeConfig); + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, jerseySeConfig) + : webServerProvider.createServer(WebServer.class, (Class) application, jerseySeConfig); final Object nativeHandle = webServer.unwrap(Object.class); final CompletionStage start = webServer.start(); final Object startResult = start.toCompletableFuture().get(); @@ -123,8 +111,15 @@ public final Set getSingletons() { protected static final class Resource { @GET @Override - public final String toString() { - return super.toString(); + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set getSingletons() { + return Collections.singleton(new Resource()); } } @@ -159,30 +154,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc // given final WebServerProvider webServerProvider = new JettyHttpServerProvider(); final Application application = new Application(); - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return SeBootstrap.Configuration.FREE_PORT; - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return TRUE; - default: - return null; - } - }; + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); @@ -192,4 +164,31 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc assertThat(webServer.port(), is(greaterThan(0))); } + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + } diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java index bbbb5dcccd..fc5fced197 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 Oracle and/or its affiliates. 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 @@ -41,6 +41,11 @@ public NettyHttpContainer(Application application) { this.appHandler.onStartup(this); } + NettyHttpContainer(Class applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass); + this.appHandler.onStartup(this); + } + @Override public ResourceConfig getConfiguration() { return appHandler.getConfiguration(); 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 dd1464969c..fece127cbc 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 @@ -51,6 +51,15 @@ final class NettyHttpServer implements WebServer { private final int port; NettyHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { + this(new NettyHttpContainer(application), configuration); + } + + NettyHttpServer(final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new NettyHttpContainer(applicationClass), configuration); + } + + NettyHttpServer(final NettyHttpContainer container, final JerseySeBootstrapConfiguration configuration) { final SSLContext sslContext = configuration.sslContext(); final SeBootstrap.Configuration.SSLClientAuthentication sslClientAuthentication = configuration .sslClientAuthentication(); @@ -58,7 +67,7 @@ final class NettyHttpServer implements WebServer { final URI uri = configuration.uri(false); this.port = NettyHttpContainerProvider.getPort(uri); - this.container = new NettyHttpContainer(application); + this.container = container; this.serverBootstrap = NettyHttpContainerProvider.createServerBootstrap( uri, this.container, 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 3400c160cb..34c700e104 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 @@ -34,10 +34,18 @@ public final class NettyHttpServerProvider implements WebServerProvider { @Override - public final T createServer(final Class type, final Application application, - final JerseySeBootstrapConfiguration configuration) { + public T createServer(final Class type, final Application application, + final JerseySeBootstrapConfiguration configuration) { return NettyHttpServer.class == type || WebServer.class == type ? type.cast(new NettyHttpServer(application, configuration)) : null; } + + @Override + public T createServer(final Class type, final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + return NettyHttpServer.class == type || WebServer.class == type + ? type.cast(new NettyHttpServer(applicationClass, configuration)) + : null; + } } 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 385a0ea6ca..3837377475 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 @@ -63,44 +63,31 @@ public final class NettyHttpServerProviderTest { @Test(timeout = 15000) - public final void shouldProvideServer() throws InterruptedException, ExecutionException { + public void shouldProvideServer2() throws InterruptedException, ExecutionException { // given - final WebServerProvider webServerProvider = new NettyHttpServerProvider(); final Resource resource = new Resource(); - final Application application = new Application() { - @Override - public final Set getSingletons() { - return Collections.singleton(resource); - } - }; - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return getPort(); - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return FALSE; - default: - return null; - } - }; + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test(timeout = 15000) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new NettyHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); - final WebServer webServer = webServerProvider.createServer(WebServer.class, application, jerseySeConfig); + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, jerseySeConfig) + : webServerProvider.createServer(WebServer.class, (Class) application, jerseySeConfig); final Object nativeHandle = webServer.unwrap(Object.class); final CompletionStage start = webServer.start(); final Object startResult = start.toCompletableFuture().get(); @@ -122,14 +109,23 @@ public final Set getSingletons() { assertThat(stopResult, is(nullValue())); } + @Path("/") protected static final class Resource { @GET @Override - public final String toString() { - return super.toString(); + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set getSingletons() { + return Collections.singleton(new Resource()); } } + private static final Logger LOGGER = Logger.getLogger(NettyHttpServerProviderTest.class.getName()); private static final int DEFAULT_PORT = 0; @@ -161,30 +157,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc // given final WebServerProvider webServerProvider = new NettyHttpServerProvider(); final Application application = new Application(); - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return SeBootstrap.Configuration.FREE_PORT; - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return TRUE; - default: - return null; - } - }; + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); @@ -194,4 +167,31 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc assertThat(webServer.port(), is(greaterThan(0))); } + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + } diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java index 327b2cf965..6e4e885516 100644 --- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java +++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021 Oracle and/or its affiliates. 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 @@ -465,4 +465,15 @@ void onServerStop() { this.appHandler = new ApplicationHandler(application, new SimpleBinder()); this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class)); } + + /** + * Create a new Simple framework HTTP container. + * + * @param applicationClass JAX-RS / Jersey application class to be deployed on Simple framework HTTP + * container. + */ + SimpleContainer(final Class applicationClass) { + this.appHandler = new ApplicationHandler(applicationClass, new SimpleBinder()); + this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class)); + } } 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 af7aec829f..e63d3f4437 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 @@ -39,7 +39,16 @@ final class SimpleHttpServer implements WebServer { private final SimpleServer simpleServer; SimpleHttpServer(final Application application, final JerseySeBootstrapConfiguration configuration) { - this.container = new SimpleContainer(application); + this(new SimpleContainer(application), configuration); + } + + SimpleHttpServer(final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + this(new SimpleContainer(applicationClass), configuration); + } + + SimpleHttpServer(final SimpleContainer container, final JerseySeBootstrapConfiguration configuration) { + this.container = container; this.simpleServer = SimpleContainerFactory.create( configuration.uri(false), configuration.sslContext(), 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 94e05abac2..c4a26a7d98 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 @@ -32,10 +32,18 @@ public final class SimpleHttpServerProvider implements WebServerProvider { @Override - public final T createServer(final Class type, final Application application, + public T createServer(final Class type, final Application application, final JerseySeBootstrapConfiguration configuration) { return SimpleHttpServer.class == type || WebServer.class == type ? type.cast(new SimpleHttpServer(application, configuration)) : null; } + + @Override + public T createServer(final Class type, final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + return SimpleHttpServer.class == type || WebServer.class == type + ? type.cast(new SimpleHttpServer(applicationClass, configuration)) + : null; + } } 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 128e4127d7..02314ea784 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 @@ -49,6 +49,7 @@ import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.WebServer; import org.glassfish.jersey.server.spi.WebServerProvider; +import org.hamcrest.CoreMatchers; import org.junit.Test; /** @@ -60,44 +61,31 @@ public final class SimpleHttpServerProviderTest { @Test(timeout = 15000) - public final void shouldProvideServer() throws InterruptedException, ExecutionException { + public void shouldProvideServer2() throws InterruptedException, ExecutionException { // given - final WebServerProvider webServerProvider = new SimpleHttpServerProvider(); final Resource resource = new Resource(); - final Application application = new Application() { - @Override - public final Set getSingletons() { - return Collections.singleton(resource); - } - }; - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return getPort(); - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return FALSE; - default: - return null; - } - }; + shouldProvideServer(ShouldProvideServerApplication.class, resource); + } + + @Test(timeout = 15000) + public void shouldProvideServerWithClass() throws InterruptedException, ExecutionException { + // given + final Resource resource = new Resource(); + final Application application = new ShouldProvideServerApplication(); + shouldProvideServer(application.getClass(), resource); + } + + private void shouldProvideServer(final Object application, final Resource resource) + throws InterruptedException, ExecutionException { + // given + final WebServerProvider webServerProvider = new SimpleHttpServerProvider(); + final SeBootstrap.Configuration configuration = configuration(getPort(), FALSE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); - final WebServer webServer = webServerProvider.createServer(WebServer.class, application, jerseySeConfig); + final WebServer webServer = Application.class.isInstance(application) + ? webServerProvider.createServer(WebServer.class, (Application) application, jerseySeConfig) + : webServerProvider.createServer(WebServer.class, (Class) application, jerseySeConfig); final Object nativeHandle = webServer.unwrap(Object.class); final CompletionStage start = webServer.start(); final Object startResult = start.toCompletableFuture().get(); @@ -123,8 +111,15 @@ public final Set getSingletons() { protected static final class Resource { @GET @Override - public final String toString() { - return super.toString(); + public String toString() { + return Resource.class.getName(); + } + } + + protected static class ShouldProvideServerApplication extends Application { + @Override + public Set getSingletons() { + return Collections.singleton(new Resource()); } } @@ -159,30 +154,7 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc // given final WebServerProvider webServerProvider = new SimpleHttpServerProvider(); final Application application = new Application(); - final SeBootstrap.Configuration configuration = name -> { - switch (name) { - case SeBootstrap.Configuration.PROTOCOL: - return "HTTP"; - case SeBootstrap.Configuration.HOST: - return "localhost"; - case SeBootstrap.Configuration.PORT: - return SeBootstrap.Configuration.FREE_PORT; - case SeBootstrap.Configuration.ROOT_PATH: - return "/"; - case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: - return SSLClientAuthentication.NONE; - case SeBootstrap.Configuration.SSL_CONTEXT: - try { - return SSLContext.getDefault(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - case ServerProperties.WEBSERVER_AUTO_START: - return TRUE; - default: - return null; - } - }; + final SeBootstrap.Configuration configuration = configuration(SeBootstrap.Configuration.FREE_PORT, TRUE); // when final JerseySeBootstrapConfiguration jerseySeConfig = JerseySeBootstrapConfiguration.from(configuration); @@ -192,4 +164,31 @@ public final void shouldScanFreePort() throws InterruptedException, ExecutionExc assertThat(webServer.port(), is(greaterThan(0))); } + private SeBootstrap.Configuration configuration(int port, boolean autoStart) { + return (SeBootstrap.Configuration) name -> { + switch (name) { + case SeBootstrap.Configuration.PROTOCOL: + return "HTTP"; + case SeBootstrap.Configuration.HOST: + return "localhost"; + case SeBootstrap.Configuration.PORT: + return port; + case SeBootstrap.Configuration.ROOT_PATH: + return "/"; + case SeBootstrap.Configuration.SSL_CLIENT_AUTHENTICATION: + return SSLClientAuthentication.NONE; + case SeBootstrap.Configuration.SSL_CONTEXT: + try { + return SSLContext.getDefault(); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + case ServerProperties.WEBSERVER_AUTO_START: + return autoStart; + default: + return null; + } + }; + } + } diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java index 4f680e146c..b21616d123 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java @@ -116,6 +116,12 @@ public CompletionStage bootstrap(Application application, return runtimeDelegate.bootstrap(application, configuration); } + @Override + public CompletionStage bootstrap(Class applicationClass, + SeBootstrap.Configuration configuration) { + return runtimeDelegate.bootstrap(applicationClass, configuration); + } + @Override public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException { return runtimeDelegate.createEntityPartBuilder(partName); diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java index 58602e2378..89e70896ca 100644 --- a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java +++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateImpl.java @@ -72,6 +72,16 @@ public CompletionStage bootstrap(Application application, throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); } + @Override + public CompletionStage bootstrap(Class applicationClass, + SeBootstrap.Configuration configuration) { + final RuntimeDelegate runtimeDelegate = findServerDelegate(); + if (runtimeDelegate != null) { + return runtimeDelegate.bootstrap(applicationClass, configuration); + } + throw new UnsupportedOperationException(LocalizationMessages.NO_CONTAINER_AVAILABLE()); + } + // TODO : Do we need multiple RuntimeDelegates? private RuntimeDelegate findServerDelegate() { for (RuntimeDelegate delegate : ServiceFinder.find(RuntimeDelegate.class)) { diff --git a/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java b/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java index de4815e2fa..2bb7d120c4 100644 --- a/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java +++ b/core-common/src/test/java/org/glassfish/jersey/internal/TestRuntimeDelegate.java @@ -60,6 +60,12 @@ public CompletionStage bootstrap(Application application, throw new UnsupportedOperationException("Not supported yet."); } + @Override + public CompletionStage bootstrap(Class aClass, + SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + public void testMediaType() { MediaType m = new MediaType("text", "plain"); Assert.assertNotNull(m); diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java index 42d11dd0cd..7d75df1b74 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java @@ -222,7 +222,20 @@ public ApplicationHandler() { * application handler. */ public ApplicationHandler(final Class jaxrsApplicationClass) { - initialize(new ApplicationConfigurator(jaxrsApplicationClass), Injections.createInjectionManager(), null); + this(jaxrsApplicationClass, null); + } + + /** + * Create a new Jersey server-side application handler configured by a + * {@link Application JAX-RS Application (sub-)class}. + * + * @param applicationClass JAX-RS {@code Application} (sub-)class that will be + * instantiated and used to configure the new Jersey + * application handler. + * @param customBinder additional custom bindings used to configure the application's. + */ + public ApplicationHandler(final Class applicationClass, final Binder customBinder) { + initialize(new ApplicationConfigurator(applicationClass), Injections.createInjectionManager(), customBinder); } /** diff --git a/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java index 8f05b7d60c..6454fc1732 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/WebServerFactory.java @@ -74,4 +74,40 @@ public static T createServer(final Class type, final Ap throw new IllegalArgumentException("No server provider supports the type " + type); } + /** + * 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 WebServerProvider} + * 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 WebServer}. + * @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 Class application, + final JerseySeBootstrapConfiguration configuration) { + for (final WebServerProvider webServerProvider : ServiceFinder.find(WebServerProvider.class)) { + final T server = webServerProvider.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/internal/RuntimeDelegateImpl.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/RuntimeDelegateImpl.java index 07d0f46de3..1af9a406bb 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 @@ -22,7 +22,6 @@ import jakarta.ws.rs.SeBootstrap; import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.EntityPart; import org.glassfish.jersey.internal.AbstractRuntimeDelegate; import org.glassfish.jersey.message.internal.MessagingBinders; import org.glassfish.jersey.server.ContainerFactory; @@ -67,48 +66,71 @@ public JerseySeBootstrapConfiguration.Builder createConfigurationBuilder() { @Override public CompletableFuture bootstrap(final Application application, final SeBootstrap.Configuration configuration) { - final JerseySeBootstrapConfiguration jerseySeConfiguration = JerseySeBootstrapConfiguration.from(configuration); + return CompletableFuture.supplyAsync(() -> { final Class httpServerClass = configuration.hasProperty(ServerProperties.WEBSERVER_CLASS) ? (Class) configuration.property(ServerProperties.WEBSERVER_CLASS) : WebServer.class; + final JerseySeBootstrapConfiguration jerseySeConfiguration + = JerseySeBootstrapConfiguration.from(configuration); + final WebServer webServer + = WebServerFactory.createServer(httpServerClass, application, jerseySeConfiguration); + return instance(configuration, webServer); + }); + } + + @SuppressWarnings("unchecked") + public CompletableFuture bootstrap(final Class applicationClass, + final SeBootstrap.Configuration configuration) { + + return CompletableFuture.supplyAsync(() -> { + final Class httpServerClass = configuration.hasProperty(ServerProperties.WEBSERVER_CLASS) + ? (Class) configuration.property(ServerProperties.WEBSERVER_CLASS) + : WebServer.class; - return new SeBootstrap.Instance() { - private final WebServer webServer = - WebServerFactory.createServer(httpServerClass, application, jerseySeConfiguration); + final JerseySeBootstrapConfiguration jerseySeConfiguration + = JerseySeBootstrapConfiguration.from(configuration); + final WebServer webServer + = WebServerFactory.createServer(httpServerClass, applicationClass, jerseySeConfiguration); + return instance(configuration, webServer); + }); + } - @Override - public final JerseySeBootstrapConfiguration configuration() { - return JerseySeBootstrapConfiguration.from(name -> { - switch (name) { + private SeBootstrap.Instance instance(final SeBootstrap.Configuration configuration, + final WebServer _webServer) { + return new SeBootstrap.Instance() { + final WebServer webServer = _webServer; + @Override + public final JerseySeBootstrapConfiguration configuration() { + return JerseySeBootstrapConfiguration.from(name -> { + switch (name) { case SeBootstrap.Configuration.PORT: return webServer.port(); case ServerProperties.WEBSERVER_CLASS: return webServer.getClass(); default: return configuration.property(name); - } - }); - } - - @Override - public final CompletionStage stop() { - return this.webServer.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.webServer) ? nativeClass.cast(this.webServer) - : this.webServer.unwrap(nativeClass); - } - }; - }); + } + }); + } + + @Override + public final CompletionStage stop() { + return this.webServer.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.webServer) ? nativeClass.cast(this.webServer) + : this.webServer.unwrap(nativeClass); + } + }; } } diff --git a/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java index 0f2322e03e..63453ee106 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/spi/WebServerProvider.java @@ -87,4 +87,26 @@ public interface WebServerProvider { T createServer(Class type, Application application, JerseySeBootstrapConfiguration configuration) throws ProcessingException; + + /** + * Creates a server of a given type which runs the given application using the + * given bootstrap configuration. + * + * @param + * the type of the web server. + * @param type + * the type of the web server. Providers SHOULD support at least + * {@link WebServer}. + * @param applicationClass + * The class of 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. + */ + T createServer(Class type, + Class applicationClass, + JerseySeBootstrapConfiguration configuration) throws ProcessingException; } diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java index dd7c562999..02343f8d4b 100644 --- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java +++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/TestRuntimeDelegate.java @@ -61,6 +61,12 @@ public CompletionStage bootstrap(Application application, throw new UnsupportedOperationException("Not supported yet."); } + @Override + public CompletionStage bootstrap(Class aClass, + SeBootstrap.Configuration configuration) { + throw new UnsupportedOperationException("Not supported yet."); + } + public void testMediaType() { MediaType m = new MediaType("text", "plain"); Assert.assertNotNull(m); diff --git a/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java b/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java index 754345b518..2831134475 100644 --- a/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java +++ b/tests/jmockit/src/test/java/org/glassfish/jersey/tests/jmockit/server/WebServerFactoryTest.java @@ -68,6 +68,14 @@ public final U createServer( ? type.cast(mockServer) : null; } + + @Override + public T createServer( + final Class type, + final Class applicationClass, + final JerseySeBootstrapConfiguration configuration) { + return null; + } } : service == InjectionManagerFactory.class ? new InjectionManagerFactory() { @Override