Skip to content

Commit

Permalink
HH-80325 jersey and spring integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Khalikov committed Aug 6, 2018
1 parent 8b654c2 commit 09aac8f
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 99 deletions.
11 changes: 10 additions & 1 deletion nab-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
<name>nuts'n'bolts application starter</name>

<properties>
<jersey.version>2.27</jersey.version>
<jetty.version>9.4.6.v20170531</jetty.version>
<jackson.version>2.6.6</jackson.version>
</properties>
Expand All @@ -33,6 +32,11 @@
</dependency>

<!-- Jersey -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring4</artifactId>
Expand Down Expand Up @@ -94,6 +98,11 @@
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
Expand Down
58 changes: 4 additions & 54 deletions nab-starter/src/main/java/ru/hh/nab/starter/NabApplication.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
package ru.hh.nab.starter;

import static java.text.MessageFormat.format;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.context.ApplicationContext;
import ru.hh.nab.common.properties.FileSettings;
import ru.hh.nab.starter.jetty.JettyFactory;
import ru.hh.nab.starter.servlet.DefaultServletConfig;
import ru.hh.nab.starter.servlet.ServletConfig;

import java.lang.management.ManagementFactory;
import java.time.LocalDateTime;
import java.util.Arrays;

public class NabApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(NabApplication.class);
Expand All @@ -27,66 +18,25 @@ public static ApplicationContext run(Class<?>... primarySources) {
}

public static ApplicationContext run(ServletConfig servletConfig, Class<?>... primarySources) {
registerSlf4JHandler();
configureLogger();
NabApplicationContext context = null;
try {
context = createApplicationContext(primarySources);
int port = startJettyServer(context, servletConfig);
printApplicationStatus(context, port);
context = new NabApplicationContext(servletConfig, primarySources);
context.refresh();
} catch (Exception e) {
logErrorAndExit(e);
}
return context;
}

private static NabApplicationContext createApplicationContext(Class<?>... primarySources) {
final NabApplicationContext context = new NabApplicationContext();
context.register(primarySources);
context.refresh();
context.registerShutdownHook();
return context;
}

public static int startJettyServer(ApplicationContext context, ServletConfig servletConfig) throws Exception {
final FileSettings settings = context.getBean(FileSettings.class);
final ServletContainer mainServlet = new ServletContainer(servletConfig.createResourceConfig(context));
final Server jettyServer = JettyFactory.create(settings, context.getBean(ThreadPool.class), mainServlet, servletConfig.getServletMapping());
servletConfig.configureServletContext((ServletContextHandler) jettyServer.getHandler(), context);
int port = startJettyServer(jettyServer);

// todo: integrate start of jetty server into spring life cycle
if (context instanceof NabApplicationContext) {
NabApplicationContext nabApplicationContext = (NabApplicationContext) context;
nabApplicationContext.setServer(jettyServer);
}

return port;
}

static void registerSlf4JHandler() {
public static void configureLogger() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}

private static int startJettyServer(Server jettyServer) throws Exception {
jettyServer.start();
return ((ServerConnector) Arrays.stream(jettyServer.getConnectors())
.filter(a -> a instanceof ServerConnector).findFirst().get())
.getLocalPort();
}

private static void printApplicationStatus(ApplicationContext context, int port) {
AppMetadata appMetadata = context.getBean(AppMetadata.class);
System.out.println(appMetadata.getStatus() + ", pid " + getCurrentPid() + ", listening to port " + port);
}

private static void logErrorAndExit(Exception e) {
LOGGER.error("Failed to start, shutting down", e);
System.err.println(format("[{0}] Failed to start, shutting down: {1}", LocalDateTime.now(), e.getMessage()));
System.exit(1);
}

private static String getCurrentPid() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,73 @@
package ru.hh.nab.starter;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import ru.hh.nab.common.properties.FileSettings;
import ru.hh.nab.starter.server.jetty.JettyServer;
import ru.hh.nab.starter.server.jetty.JettyServerFactory;
import ru.hh.nab.starter.servlet.ServletConfig;

class NabApplicationContext extends AnnotationConfigWebApplicationContext {
import java.lang.management.ManagementFactory;

private volatile Server server;
public class NabApplicationContext extends AnnotationConfigWebApplicationContext {

private volatile JettyServer jettyServer;

private final ServletConfig servletConfig;

public NabApplicationContext(ServletConfig servletConfig, Class<?>... primarySources) {
this.servletConfig = servletConfig;
register(primarySources);
registerShutdownHook();
}

@Override
protected void finishRefresh() {
super.finishRefresh();
startJettyServer();
printStartupInfo();
}

private void startJettyServer() {
JettyServer jettyServer = this.jettyServer;
try {
if (jettyServer == null) {
FileSettings jettySettings = getBean(FileSettings.class);
ThreadPool threadPool = getBean(ThreadPool.class);
ResourceConfig resourceConfig = getBean(ResourceConfig.class);

this.jettyServer = JettyServerFactory.create(jettySettings, threadPool, resourceConfig, servletConfig, (contextHandler) -> {
configureServletContext(contextHandler, this, servletConfig);
setServletContext(contextHandler.getServletContext());
});

this.jettyServer.start();
}
} catch (Throwable t) {
throw new ApplicationContextException("Unable to start application server", t);
}
}

public static void configureServletContext(ServletContextHandler handler, ApplicationContext applicationContext, ServletConfig servletConfig) {
handler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
servletConfig.configureServletContext(handler, applicationContext);
}

boolean isServerRunning() {
return server.isRunning();
return jettyServer.isRunning();
}

private void printStartupInfo() {
AppMetadata appMetadata = getBean(AppMetadata.class);
System.out.println(appMetadata.getStatus() + ", pid " + getCurrentPid());
}

void setServer(Server server) {
this.server = server;
private static String getCurrentPid() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import org.springframework.context.annotation.Configuration;
import ru.hh.nab.common.executor.ScheduledExecutor;
import ru.hh.nab.common.properties.FileSettings;
import static ru.hh.nab.starter.jetty.JettyFactory.createJettyThreadPool;
import static ru.hh.nab.starter.server.jetty.JettyServerFactory.createJettyThreadPool;

import java.util.concurrent.ScheduledExecutorService;

Expand Down
37 changes: 26 additions & 11 deletions nab-starter/src/main/java/ru/hh/nab/starter/NabProdConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,27 @@
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.timgroup.statsd.StatsDClient;
import org.eclipse.jetty.servlet.FilterHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.support.MBeanServerFactoryBean;
import ru.hh.metrics.StatsDSender;
import ru.hh.nab.starter.filters.ResourceNameLoggingFilter;
import ru.hh.nab.starter.jersey.FilteredXmlElementProvider;
import ru.hh.nab.starter.jersey.FilteredXmlListElementProvider;
import ru.hh.nab.starter.jersey.FilteredXmlRootElementProvider;
import ru.hh.nab.starter.jmx.MBeanExporterFactory;
import ru.hh.nab.common.properties.FileSettings;

import javax.management.MBeanServer;
import java.util.Properties;
import java.util.concurrent.ScheduledExecutorService;

import static ru.hh.nab.starter.jetty.HttpCacheFilterFactory.createCacheFilterHolder;
import ru.hh.nab.starter.resource.StatsResource;
import ru.hh.nab.starter.resource.StatusResource;
import static ru.hh.nab.starter.server.cache.HttpCacheFilterFactory.createCacheFilterHolder;
import static ru.hh.nab.common.properties.PropertiesUtils.fromFilesInSettingsDir;

@Configuration
Expand All @@ -29,6 +36,24 @@ FileSettings fileSettings() throws Exception {
return new FileSettings(properties);
}

@Bean
ResourceConfig resourceConfig() {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(FilteredXmlRootElementProvider.App.class);
resourceConfig.register(FilteredXmlRootElementProvider.General.class);
resourceConfig.register(FilteredXmlRootElementProvider.Text.class);
resourceConfig.register(FilteredXmlElementProvider.App.class);
resourceConfig.register(FilteredXmlElementProvider.General.class);
resourceConfig.register(FilteredXmlElementProvider.Text.class);
resourceConfig.register(FilteredXmlListElementProvider.App.class);
resourceConfig.register(FilteredXmlListElementProvider.General.class);
resourceConfig.register(FilteredXmlListElementProvider.Text.class);
resourceConfig.register(new ResourceNameLoggingFilter());
resourceConfig.register(StatusResource.class);
resourceConfig.register(StatsResource.class);
return resourceConfig;
}

@Bean
StatsDClient statsDClient() {
return new NonBlockingStatsDClient(null, "localhost", 8125, 10000);
Expand Down Expand Up @@ -58,14 +83,4 @@ MBeanServerFactoryBean mBeanServerFactoryBean() {
MBeanExporter mBeanExporter(FileSettings settings, MBeanServer mbeanServer) {
return MBeanExporterFactory.create(settings, mbeanServer);
}

@Bean
StatusResource statusResource(AppMetadata appMetadata) {
return new StatusResource(appMetadata);
}

@Bean
StatsResource statsResource() {
return new StatsResource();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ru.hh.nab.starter;
package ru.hh.nab.starter.resource;

import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/stats")
@Singleton
public class StatsResource {
@GET
@Produces("text/csv")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package ru.hh.nab.starter;
package ru.hh.nab.starter.resource;

import ru.hh.nab.starter.AppMetadata;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/status")
@Singleton
public class StatusResource {

private final AppMetadata appMetaData;

@Inject
public StatusResource(AppMetadata appMetaData) {
this.appMetaData = appMetaData;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package ru.hh.nab.starter.servlet;

import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.request.RequestContextListener;
import ru.hh.nab.starter.filters.RequestIdLoggingFilter;
import ru.hh.nab.starter.filters.ResourceNameLoggingFilter;
import ru.hh.nab.starter.jersey.FilteredXmlElementProvider;
import ru.hh.nab.starter.jersey.FilteredXmlListElementProvider;
import ru.hh.nab.starter.jersey.FilteredXmlRootElementProvider;

import javax.servlet.DispatcherType;
import java.util.EnumSet;

public class DefaultServletConfig implements ServletConfig {

Expand All @@ -29,22 +26,6 @@ public void configureServletContext(ServletContextHandler servletContextHandler,
}

@Override
public ResourceConfig createResourceConfig(ApplicationContext context) {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.property("contextConfig", context);
context.getBeansWithAnnotation(javax.ws.rs.Path.class)
.forEach((name, resource) -> resourceConfig.register(resource));

resourceConfig.register(FilteredXmlRootElementProvider.App.class);
resourceConfig.register(FilteredXmlRootElementProvider.General.class);
resourceConfig.register(FilteredXmlRootElementProvider.Text.class);
resourceConfig.register(FilteredXmlElementProvider.App.class);
resourceConfig.register(FilteredXmlElementProvider.General.class);
resourceConfig.register(FilteredXmlElementProvider.Text.class);
resourceConfig.register(FilteredXmlListElementProvider.App.class);
resourceConfig.register(FilteredXmlListElementProvider.General.class);
resourceConfig.register(FilteredXmlListElementProvider.Text.class);
resourceConfig.register(new ResourceNameLoggingFilter());
return resourceConfig;
public void registerResources(ResourceConfig resourceConfig) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.hh.nab.starter.servlet;

import org.eclipse.jetty.servlet.ServletContextHandler;

@FunctionalInterface
public interface JerseyServletContextInitializer {

void onStartup(ServletContextHandler contextHandler);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ default String getServletMapping() {

void configureServletContext(ServletContextHandler servletContextHandler, ApplicationContext applicationContext);

ResourceConfig createResourceConfig(ApplicationContext context);
void registerResources(ResourceConfig resourceConfig);
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

<properties>
<spring.version>5.0.3.RELEASE</spring.version>
<jersey.version>2.27</jersey.version>
<hibernate.version>5.2.10.Final</hibernate.version>
<postgres.jdbc.version>42.2.2</postgres.jdbc.version>
<hhmetrics.version>0.16</hhmetrics.version>
Expand Down

0 comments on commit 09aac8f

Please sign in to comment.