diff --git a/nab-starter/pom.xml b/nab-starter/pom.xml
index 0276697ac..769980915 100644
--- a/nab-starter/pom.xml
+++ b/nab-starter/pom.xml
@@ -14,7 +14,6 @@
nuts'n'bolts application starter
- 2.27
9.4.6.v20170531
2.6.6
@@ -33,6 +32,11 @@
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+
org.glassfish.jersey.ext
jersey-spring4
@@ -94,6 +98,11 @@
jetty-servlet
${jetty.version}
+
+ org.eclipse.jetty
+ jetty-webapp
+ ${jetty.version}
+
org.eclipse.jetty
jetty-jmx
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/NabApplication.java b/nab-starter/src/main/java/ru/hh/nab/starter/NabApplication.java
index 13ca69459..7e7f6c631 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/NabApplication.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/NabApplication.java
@@ -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);
@@ -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];
- }
}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/NabApplicationContext.java b/nab-starter/src/main/java/ru/hh/nab/starter/NabApplicationContext.java
index 5c9a74cc5..f892b9f1a 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/NabApplicationContext.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/NabApplicationContext.java
@@ -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];
}
}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/NabCommonConfig.java b/nab-starter/src/main/java/ru/hh/nab/starter/NabCommonConfig.java
index a4807b0a9..774c180f2 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/NabCommonConfig.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/NabCommonConfig.java
@@ -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;
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/NabProdConfig.java b/nab-starter/src/main/java/ru/hh/nab/starter/NabProdConfig.java
index dc2e3aaa1..b65d9096e 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/NabProdConfig.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/NabProdConfig.java
@@ -3,12 +3,17 @@
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;
@@ -16,7 +21,9 @@
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
@@ -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);
@@ -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();
- }
}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/StatsResource.java b/nab-starter/src/main/java/ru/hh/nab/starter/resource/StatsResource.java
similarity index 73%
rename from nab-starter/src/main/java/ru/hh/nab/starter/StatsResource.java
rename to nab-starter/src/main/java/ru/hh/nab/starter/resource/StatsResource.java
index b2406a981..5c95faa24 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/StatsResource.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/resource/StatsResource.java
@@ -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")
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/StatusResource.java b/nab-starter/src/main/java/ru/hh/nab/starter/resource/StatusResource.java
similarity index 80%
rename from nab-starter/src/main/java/ru/hh/nab/starter/StatusResource.java
rename to nab-starter/src/main/java/ru/hh/nab/starter/resource/StatusResource.java
index 4b669989c..711dc0095 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/StatusResource.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/resource/StatusResource.java
@@ -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;
}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/servlet/DefaultServletConfig.java b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/DefaultServletConfig.java
index c8d59efbf..6215da7bc 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/servlet/DefaultServletConfig.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/DefaultServletConfig.java
@@ -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 {
@@ -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) {
}
}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/servlet/JerseyServletContextInitializer.java b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/JerseyServletContextInitializer.java
new file mode 100644
index 000000000..d122eed81
--- /dev/null
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/JerseyServletContextInitializer.java
@@ -0,0 +1,9 @@
+package ru.hh.nab.starter.servlet;
+
+import org.eclipse.jetty.servlet.ServletContextHandler;
+
+@FunctionalInterface
+public interface JerseyServletContextInitializer {
+
+ void onStartup(ServletContextHandler contextHandler);
+}
diff --git a/nab-starter/src/main/java/ru/hh/nab/starter/servlet/ServletConfig.java b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/ServletConfig.java
index 9d478b97d..d618467f3 100644
--- a/nab-starter/src/main/java/ru/hh/nab/starter/servlet/ServletConfig.java
+++ b/nab-starter/src/main/java/ru/hh/nab/starter/servlet/ServletConfig.java
@@ -12,5 +12,5 @@ default String getServletMapping() {
void configureServletContext(ServletContextHandler servletContextHandler, ApplicationContext applicationContext);
- ResourceConfig createResourceConfig(ApplicationContext context);
+ void registerResources(ResourceConfig resourceConfig);
}
diff --git a/pom.xml b/pom.xml
index 19c4a02ca..9f716e4e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,7 @@
5.0.3.RELEASE
+ 2.27
5.2.10.Final
42.2.2
0.16