package com.netflix.governator.guice.jersey; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Proxy; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import java.util.function.UnaryOperator; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.junit.Assert; import org.junit.Test; import com.google.common.io.CharStreams; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.util.Modules; import com.netflix.governator.InjectorBuilder; import com.netflix.governator.LifecycleInjector; import com.netflix.governator.ShutdownHookModule; import com.netflix.governator.guice.jetty.DefaultJettyConfig; import com.netflix.governator.guice.jetty.JettyConfig; import com.netflix.governator.guice.jetty.JettyModule; import com.netflix.governator.guice.jetty.resources3.SampleResource; import com.netflix.governator.providers.Advises; import com.sun.jersey.api.core.DefaultResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.guice.JerseyServletModule; public class JerseyServerTest { @Test public void confirmResourceLoadedWithoutBinding() throws IOException { // Create the injector and autostart Jetty try (LifecycleInjector injector = InjectorBuilder.fromModules( new ShutdownHookModule(), new GovernatorJerseySupportModule(), new JerseyServletModule() { @Override protected void configureServlets() { serve("/*").with(GovernatorServletContainer.class); } @Advises @Singleton @Named("governator") UnaryOperator<DefaultResourceConfig> getResourceConfig() { return config -> { Map<String, Object> props = config.getProperties(); props.put(ResourceConfig.FEATURE_DISABLE_WADL, "false"); config.getClasses().add(SampleResource.class); return config; }; } }, Modules.override(new JettyModule()) .with(new AbstractModule() { @Override protected void configure() { } @Provides JettyConfig getConfig() { // Use emphemeral ports return new DefaultJettyConfig().setPort(0); } })) .createInjector()) { // Determine the emphermal port from jetty Server server = injector.getInstance(Server.class); int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); System.out.println("Listening on port : "+ port); URL url = new URL(String.format("http://localhost:%d/", port)); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); Assert.assertEquals(200, conn.getResponseCode()); }; } @Test public void confirmFailedToCreateWithoutRootResources() { // Create the injector and autostart Jetty try (LifecycleInjector injector = InjectorBuilder.fromModules( new ShutdownHookModule(), new GovernatorJerseySupportModule(), new JerseyServletModule() { protected void configureServlets() { serve("/*").with(GovernatorServletContainer.class); } }, Modules.override(new JettyModule()) .with(new AbstractModule() { @Override protected void configure() { } @Provides JettyConfig getConfig() { // Use emphemeral ports return new DefaultJettyConfig().setPort(0); } })) .createInjector()) { Assert.fail(); } catch (Exception e) { Assert.assertTrue(e.getCause().getMessage().contains("The ResourceConfig instance does not contain any root resource classes")); } } @Test public void confirmNoResourceLoadedFromGuiceBinding() throws InterruptedException, MalformedURLException, IOException { try (LifecycleInjector injector = InjectorBuilder.fromModules( new ShutdownHookModule(), new GovernatorJerseySupportModule(), new JerseyServletModule() { protected void configureServlets() { serve("/*").with(GovernatorServletContainer.class); bind(SampleResource.class); } }, Modules.override(new JettyModule()) .with(new AbstractModule() { @Override protected void configure() { } @Provides JettyConfig getConfig() { // Use emphemeral ports return new DefaultJettyConfig().setPort(0); } })) .createInjector()) { Assert.fail(); } catch (Exception e) { Assert.assertTrue(e.getCause().getMessage().contains("The ResourceConfig instance does not contain any root resource classes")); } } @Path("/") @Singleton public static class FieldInjectionResource { private static int createCount = 0; public FieldInjectionResource() { createCount++; } @Inject private String foo; @Context UriInfo uri; @GET public String get() { return foo; } } @Test public void confirmNonJerseySingletonNotEagerOrASingleton() { // Create the injector and autostart Jetty try (LifecycleInjector injector = InjectorBuilder.fromModules( new ShutdownHookModule(), new GovernatorJerseySupportModule(), new JerseyServletModule() { protected void configureServlets() { serve("/*").with(GovernatorServletContainer.class); bind(String.class).toInstance("foo"); } @Advises @Singleton @Named("governator") UnaryOperator<DefaultResourceConfig> getResourceConfig() { return config -> { config.getClasses().add(FieldInjectionResource.class); return config; }; } }, Modules.override(new JettyModule()) .with(new AbstractModule() { @Override protected void configure() { } @Provides JettyConfig getConfig() { // Use emphemeral ports return new DefaultJettyConfig().setPort(0); } })) .createInjector()) { Assert.assertEquals(0, FieldInjectionResource.createCount); // Determine the emphermal port from jetty Server server = injector.getInstance(Server.class); int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); System.out.println("Listening on port : "+ port); URL url = new URL(String.format("http://localhost:%d/", port)); { HttpURLConnection conn = (HttpURLConnection)url.openConnection(); Assert.assertEquals(200, conn.getResponseCode()); Assert.assertEquals(1, FieldInjectionResource.createCount); } { HttpURLConnection conn = (HttpURLConnection)url.openConnection(); Assert.assertEquals(200, conn.getResponseCode()); Assert.assertEquals(2, FieldInjectionResource.createCount); } } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } @Path("/") @com.sun.jersey.spi.resource.Singleton public static class UriContextIsRequestScoped { @Context UriInfo uri; @GET @Path("{subResources:.*}") public String get(@PathParam("subResources") String subResources) { Assert.assertTrue(Proxy.isProxyClass(uri.getClass())); return uri.getPath(); } } @Test public void confirmUriInfoContextIsRequestScoped() { // Create the injector and autostart Jetty try (LifecycleInjector injector = InjectorBuilder.fromModules( new ShutdownHookModule(), new GovernatorJerseySupportModule(), new JerseyServletModule() { protected void configureServlets() { serve("/*").with(GovernatorServletContainer.class); bind(String.class).toInstance("foo"); } @Advises @Singleton @Named("governator") UnaryOperator<DefaultResourceConfig> getResourceConfig() { return config -> { config.getClasses().add(UriContextIsRequestScoped.class); return config; }; } }, Modules.override(new JettyModule()) .with(new AbstractModule() { @Override protected void configure() { } @Provides JettyConfig getConfig() { // Use emphemeral ports return new DefaultJettyConfig().setPort(0); } })) .createInjector()) { // Determine the emphermal port from jetty Server server = injector.getInstance(Server.class); int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); System.out.println("Listening on port : "+ port); { URL url = new URL(String.format("http://localhost:%d/path1", port)); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); Assert.assertEquals(200, conn.getResponseCode()); Assert.assertEquals("path1", CharStreams.toString(new InputStreamReader(conn.getInputStream()))); } { URL url = new URL(String.format("http://localhost:%d/path2", port)); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); Assert.assertEquals(200, conn.getResponseCode()); Assert.assertEquals("path2", CharStreams.toString(new InputStreamReader(conn.getInputStream()))); } } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } }