package com.fredhopper.server;
import java.util.ServiceLoader;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import com.fredhopper.environment.Environment;
import com.fredhopper.lifecycle.AbstractLifeCycle;
import com.fredhopper.lifecycle.Container;
import com.fredhopper.lifecycle.LifeCycle;
import com.fredhopper.server.spi.LoggingConfigurator;
/**
* A wrapper {@link LifeCycle} that manages an instance of
* Jetty's {@link Server}. The server uses
* {@link HandlerCollectionLoader} to load all the available
* implementations on the class path and adds the result as the
* default {@link Handler} of this server.
* <p>
* The {@link EmbeddedServer} can be created using
* {@link #createEmbeddedServer()} or
* {@link #createServer(Environment)}. This way it is ensured
* that {@link LifeCycle} management of the server occurs in
* separate threads.
*/
public class EmbeddedServer extends AbstractLifeCycle {
/**
* The single instance of {@link Environment} for all
* instances of {@link EmbeddedServer}s in this JVM.
*/
private static final Environment ENVIRONMENT;
static {
/*
* 1. Load a common single instance of Environment. 2.
* Configure logging via ServiceLoader
*/
ENVIRONMENT = Environment.createEnvironment();
ServiceLoader<LoggingConfigurator> loader =
ServiceLoader.<LoggingConfigurator>load(LoggingConfigurator.class);
for (LoggingConfigurator lc : loader) {
lc.configure(ENVIRONMENT);
}
}
/**
* The prefix used by Jetty when logging HTTP requests; e.g.
* <code>http-NNN</code>.
*/
private static final String DEFAULT_JETTY_THREAD_NAME = "http";
/**
* Creates an instance {@link EmbeddedServer} using
* {@link Environment#createEnvironment()}.
*
* @return an instance {@link LifeCycle} wrapping around the
* server
*/
public static LifeCycle createEmbeddedServer() {
return createEmbeddedServer(ENVIRONMENT);
}
/**
* Creates an instance of {@link EmbeddedServer}.
*
* @param environment the environment of the server
* @return an instance {@link LifeCycle} wrapping around the
* server
*/
public static LifeCycle createEmbeddedServer(Environment environment) {
EmbeddedServer server = new EmbeddedServer(environment);
Container container = new Container(server, true, true);
return container;
}
private final Server server;
private final Environment environment;
/**
* Ctor
*
* @param environment the environment of the server
*/
public EmbeddedServer(Environment environment) {
this.environment = environment;
this.server = createServer(environment);
}
@Override
protected void doInitLifeCycle() throws Exception {
HandlerCollectionLoader handlers = new HandlerCollectionLoader();
server.setHandler(handlers.apply(environment));
}
@Override
protected void doStartLifeCycle() throws Exception {
this.server.start();
}
@Override
protected void doStopLifeCycle() throws Exception {
this.server.stop();
}
/**
* Creates an instance of Jetty's server using
* {@link Environment}. The provided {@link Environment}
* specifies the host ({@link Environment#getServerHost()})
* and the port ({@link Environment#getServerPort()}) of the
* server.
*
* @param environment the environment of the server
* @return the Jetty's {@link Server}
*/
protected Server createServer(Environment environment) {
final QueuedThreadPool qtp = new QueuedThreadPool(1024, 16, 30);
qtp.setName(DEFAULT_JETTY_THREAD_NAME);
final Server server = new Server(qtp);
final ServerConnector connector = new ServerConnector(server);
connector.setHost(environment.getServerHost());
connector.setPort(environment.getServerPort());
server.addConnector(connector);
return server;
}
protected final Server getServer() {
return server;
}
}