org.terracotta.management.embedded.StandaloneServer Maven / Gradle / Ivy
/* All content copyright (c) 2003-2012 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.*/
package org.terracotta.management.embedded;
import java.util.EnumSet;
import java.util.EventListener;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.glassfish.jersey.servlet.ServletContainer;
/**
* A standalone server implementation for agents embedded at the Terracotta monitorable entity.
*
* @author Ludovic Orban
* @author brandony
*/
public final class StandaloneServer implements StandaloneServerInterface {
public static final String EMBEDDED_CTXT = "/tc-management-api";
private final List filterDetails;
private final List servletListeners;
private volatile Server server;
private final String applicationClassName;
private final String host;
private final int port;
private final SSLContext sslCtxt;
private final boolean needClientAuth;
/**
* Create a standalone management server.
* @param filterDetails a list of {@link FilterDetail} to add. Can be null;
* @param servletListeners a list of {@link ServletContextListener} to add. Can be null.
* @param applicationClassName the {@link javax.ws.rs.core.Application} implementation to deploy.
* @param host the host or IP address to bind. Mandatory unless port is < 0.
* @param port the port to bind. Can be < 0 to mean do not bind.
* @param sslCtxt the {@link SSLContext} to use. Can be null if no SSL is desired.
* @param needClientAuth true to mandate client SSL auth, false otherwise.
*/
public StandaloneServer(List filterDetails, List servletListeners, String applicationClassName,
String host, int port, SSLContext sslCtxt, boolean needClientAuth) {
super();
this.filterDetails = filterDetails;
this.servletListeners = servletListeners;
this.applicationClassName = applicationClassName;
this.host = host;
this.port = port;
this.sslCtxt = sslCtxt;
this.needClientAuth = needClientAuth;
}
@Override
public void start() throws Exception {
if (port < 0) {
return;
}
if (port == 0) {
throw new IllegalArgumentException("port must be set");
}
if (applicationClassName == null) {
throw new IllegalArgumentException("applicationClassName must be set");
}
if (server != null) {
throw new IllegalStateException("server already started");
}
try {
// Create a basic jetty server object without declaring the port. Since we are configuring connectors
// directly we'll be setting ports on those connectors.
server = new Server();
// HttpConfiguration is a collection of configuration information appropriate for http and https. The default
// scheme for http is http
of course, as the default for secured http is https
but
// we show setting the scheme to show it can be done. The port for secured communication is also set here.
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
httpConfig.setSecurePort(port);
ServerConnector connector;
if (sslCtxt != null) {
// A new HttpConfiguration object is needed for the next connector and you can pass the old one as an
// argument to effectively clone the contents. On this HttpConfiguration object we add a
// SecureRequestCustomizer which is how a new connector is able to resolve the https connection before
// handing control over to the Jetty Server.
HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setSslContext(sslCtxt);
sslContextFactory.setNeedClientAuth(needClientAuth);
// HTTPS connector
// We create a second ServerConnector, passing in the http configuration we just made along with the
// previously created ssl context factory. Next we set the port and a longer idle timeout.
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory(httpsConfig));
} else {
// HTTP connector
// The first server connector we create is the one for http, passing in the http configuration we configured
// above so it can get things like the output buffer size, etc. We also set the port (8080) and configure an
// idle timeout.
connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
}
connector.setHost(host);
connector.setPort(port);
server.setConnectors(new Connector[]{connector});
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath(EMBEDDED_CTXT);
server.setHandler(context);
ServletHolder servletHolder = new ServletHolder(new ServletContainer());
// make sure com.sun.jersey.core.util.FeaturesAndProperties.FEATURE_XMLROOTELEMENT_PROCESSING is set to true
// so that a list of @XmlRootElement(name = "configuration") is
servletHolder.setInitParameter("com.sun.jersey.config.feature.XmlRootElementProcessing", "true");
servletHolder.setInitParameter("javax.ws.rs.Application", applicationClassName);
// not needed anymore thanks to the jackson-jaxrs-json-provider
// servletHolder.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
"com.sun.jersey.api.container.filter.GZIPContentEncodingFilter");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
"com.sun.jersey.api.container.filter.GZIPContentEncodingFilter");
context.addServlet(servletHolder, "/*");
if (servletListeners != null) {
context.setEventListeners(servletListeners.toArray(new EventListener[] {}));
}
if (filterDetails != null) {
for (FilterDetail f : filterDetails) {
FilterHolder filterHolder = new FilterHolder(f.getFilter());
EnumSet dTypes = null;
if (f.getDispatcherNames() != null) {
dTypes = EnumSet.noneOf(DispatcherType.class);
for (String dn : f.getDispatcherNames()) {
dTypes.add(DispatcherType.valueOf(dn));
}
}
context.addFilter(filterHolder, f.getPathSpec(), dTypes);
}
}
server.start();
} catch (Exception e) {
server.stop();
server = null;
throw e;
}
}
@Override
public void stop() throws Exception {
if (server == null || port < 0) {
return;
}
try {
server.stop();
server.join();
} finally {
server = null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy