curl -v http://localhost:9103/some/path # Calls a handler and does something RESTful curl -v http://localhost:9103/stop # Stops the Jetty instancecurl -v http://localhost:9103/restart # Restarts the Jetty instanceFirst up create a main class:
package com.company;import org.eclipse.jetty.server.Handler;import org.eclipse.jetty.server.NCSARequestLog;import org.eclipse.jetty.server.Server;import org.eclipse.jetty.server.handler.ContextHandlerCollection;import org.eclipse.jetty.server.handler.HandlerCollection;import org.eclipse.jetty.server.handler.RequestLogHandler;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class EmbeddedJetty { private static Logger log = LoggerFactory.getLogger(EmbeddedJetty.class); public static void main(String[] args) throws Exception { while (true) { // Realistically all parameters should be read from some external file... log.info("Starting Jetty on port 9103"); Server server = new Server(9103); HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection contexts = new ContextHandlerCollection(); // I added this to show how to add access logs to an embedded server. RequestLogHandler requestLogHandler = new RequestLogHandler(); NCSARequestLog requestLog = new NCSARequestLog("/tmp/jetty-yyyy_mm_dd.request.log"); requestLog.setAppend(true); requestLog.setExtended(true); requestLog.setLogTimeZone("UTC"); requestLogHandler.setRequestLog(requestLog); // We want the server to gracefully allow current requests to stop server.setGracefulShutdown(1000); server.setStopAtShutdown(true); // Now add the handlers YourHandler yourHandler = new YourHandler(server); handlers.setHandlers(new Handler[]{contexts, yourHandler, requestLogHandler}); server.setHandler(handlers); // Start the server server.start(); server.join(); // It's stopped. log.info("Jetty stopped"); if (!yourHandler.restartPlease) { break; } log.warn("Restarting Jetty"); } }}Now the handler:
package com.company;import java.io.IOException;import java.net.URI;import java.net.URISyntaxException;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.eclipse.jetty.server.Request;import org.eclipse.jetty.server.Server;import org.eclipse.jetty.server.handler.AbstractHandler;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class YourHandler extends AbstractHandler { private static Logger log = LoggerFactory.getLogger(YourHandler.class); private Server server = null; public Boolean restartPlease = false; public YourHandler(Server server) { this.server = server; } private boolean stopServer(HttpServletResponse response) throws IOException { log.warn("Stopping Jetty"); response.setStatus(202); response.setContentType("text/plain"); ServletOutputStream os = response.getOutputStream(); os.println("Shutting down."); os.close(); response.flushBuffer(); try { // Stop the server. new Thread() { @Override public void run() { try { log.info("Shutting down Jetty..."); server.stop(); log.info("Jetty has stopped."); } catch (Exception ex) { log.error("Error when stopping Jetty: " + ex.getMessage(), ex); } } }.start(); } catch (Exception ex) { log.error("Unable to stop Jetty: " + ex); return false; } return true; } @Override public void handle(String string, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String pathInfo = request.getPathInfo(); // THIS SHOULD OBVIOUSLY BE SECURED!!! if ("/stop".equals(pathInfo)) { stopServer(response); return; } if ("/restart".equals(pathInfo)) { restartPlease = true; stopServer(response); return; } // Go off and do the rest of your RESTful calls... // And close off how you please response.sendRedirect("http://nowhere.com"); }}And you can now run your main class from your IDE of choice. Just for reference I added a log4j.properties:
# Sitelog4j.logger.com.company=DEBUG, SITE_CONSOLElog4j.additivity.com.company=false# Set root logger levellog4j.rootLogger=DEBUG, CONSOLElog4j.logger.org.eclipse=INFO, CONSOLElog4j.additivity.org.eclipse=false# ---------------------------------------------------------------------------------# Appenders - Notice I have added a discriminator to the conversion pattern# --------------------------------------------------------------------------------- # For console logging - not in production obviously as you'd use a rolling file appenderlog4j.appender.SITE_CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.SITE_CONSOLE.layout=org.apache.log4j.EnhancedPatternLayoutlog4j.appender.SITE_CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS}{UTC} SITE %-5p [%t] %c{1.} %x - %m%n# The baseline CONSOLE loggerlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.layout=org.apache.log4j.EnhancedPatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS}{UTC} JETTY %-5p [%t] %c{1.} %x - %m%nI created a plain Java SE app and added a 'lib' folder with these jars in it:
jetty-continuation-8.0.4.v20111024.jarjetty-http-8.0.4.v20111024.jarjetty-io-8.0.4.v20111024.jarjetty-server-8.0.4.v20111024.jarjetty-servlet-8.0.4.v20111024.jarjetty-servlets-8.0.4.v20111024.jarjetty-util-8.0.4.v20111024.jarjetty-webapp-8.0.4.v20111024.jarlog4j-1.2.16.jarservlet-api-3.0.jarslf4j-api-1.6.2.jarslf4j-log4j12-1.6.2.jarFrom the Jetty8 release. I then ensured that the MANIFEST included these jars. Just for reference the META-INF/MANIFEST.MF looks like this:
cat META-INF/MANIFEST.MF Manifest-Version: 1.0Ant-Version: Apache Ant 1.8.2Created-By: 1.6.0_29-b11-402-10M3527 (Apple Inc.)Class-Path: lib/jetty-all-8.0.4.v20111024-javadoc.jar lib/jetty-contin uation-8.0.4.v20111024.jar lib/jetty-http-8.0.4.v20111024.jar lib/jet ty-io-8.0.4.v20111024.jar lib/jetty-server-8.0.4.v20111024.jar lib/je tty-servlet-8.0.4.v20111024.jar lib/jetty-servlets-8.0.4.v20111024.ja r lib/jetty-util-8.0.4.v20111024.jar lib/jetty-webapp-8.0.4.v20111024 .jar lib/log4j-1.2.16.jar lib/servlet-api-3.0.jar lib/slf4j-api-1.6.2 .jar lib/slf4j-log4j12-1.6.2.jarX-COMMENT: Main-Class will be added automatically by buildMain-Class: com.company.EmbeddedJettyI know I included the javadoc un-intentionally... This scheme requires a lib folder alongside the jar with those files in it. (Need to figure out how to bundle the Jetty8 jars so that the app is self-contained...) So the jar can be started like this:
java -jar /some/folder/EmbeddedJetty/dist/EmbeddedJetty.jar