Embedded Jetty
One of the coolest things about Jetty is the ability to run it in embedded mode. This means that you can write a Java app with a main method that will launch a Jetty server. This has some really nice benefits. For example, it makes it really easy to deploy a server to EC2 because all you need to do is transfer your jar file there and hit run – no need to setup a servlet container, etc. Also, it makes it possible to dynamically set servlet parameters such as Struts 2 devMode. You can set a flag on the command line, parse it using a library such as JCommander, and then run in development mode depending upon what was requested by the flag passed in.
You first need to get the relevant jars included in your project as dependencies. All of the dependencies are available in Maven repositories. I use Gradle, so you may not be familiar with the syntax below, but you can take the parts between the colons and enter them as the groupId, artifactId, and version if you’re using Maven.
compile 'org.eclipse.jetty:jetty-io:8.0.0.M3'
compile 'org.eclipse.jetty:jetty-server:8.0.0.M3'
compile 'org.eclipse.jetty:jetty-servlet:8.0.0.M3'
compile 'org.eclipse.jetty:jetty-util:8.0.0.M3'
compile 'org.eclipse.jetty:jetty-webapp:8.0.0.M3'
compile 'org.mortbay.jetty:jsp-2.1-glassfish:2.1.v20100127'
Here’s an example of running a web app in Jetty’s embedded mode:
package com.benmccann.example.server;
import java.net.URL;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceFilter;
/**
* @author benmccann.com
*/
public class WebServer {
private final Server server;
public WebServer() {
this.server = createNewServer();
}
private Server createNewServer() {
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(8080);
server.addConnector(connector);
WebAppContext webApp = new WebAppContext(getBaseUrl(), "/");
webApp.addEventListener(new GuiceListener());
ServletHandler handler = createServletHandler();
webApp.setServletHandler(handler);
webApp.setErrorHandler(createErrorHandler());
server.setHandler(webApp);
return server;
}
private ErrorHandler createErrorHandler() {
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.addErrorPage(500, "/error.html");
return errorHandler;
}
private ServletHandler createServletHandler() {
ServletHandler servletHandler = new ServletHandler();
FilterHolder guiceFilterHolder = createGuiceFilterHolder();
servletHandler.addFilter(guiceFilterHolder,
createFilterMapping("/*", guiceFilterHolder));
FilterHolder strutsFilterHolder = createStrutsFilterHolder();
servletHandler.addFilter(strutsFilterHolder,
createFilterMapping("/*", strutsFilterHolder));
return servletHandler;
}
private FilterHolder createGuiceFilterHolder() {
FilterHolder filterHolder = new FilterHolder(GuiceFilter.class);
filterHolder.setName("guice");
return filterHolder;
}
private FilterHolder createStrutsFilterHolder() {
FilterHolder filterHolder
= new FilterHolder(StrutsPrepareAndExecuteFilter.class);
filterHolder.setName("struts2");
filterHolder.setInitParameter("struts.devMode", "true");
return filterHolder;
}
private FilterMapping createFilterMapping(
String pathSpec, FilterHolder filterHolder) {
FilterMapping filterMapping = new FilterMapping();
filterMapping.setPathSpec(pathSpec);
filterMapping.setFilterName(filterHolder.getName());
return filterMapping;
}
public void run() throws Exception {
server.start();
server.join();
}
private String getBaseUrl() {
URL webInfUrl = WebServer.class.getClassLoader().getResource("WEB-INF");
String webInfUrlString = webInfUrl.toExternalForm();
return webInfUrlString.substring(0, webInfUrlString.lastIndexOf('/') + 1);
}
public static void main(String[] args) throws Exception {
WebServer server = new WebServer();
server.run();
}
}
This web app used the Struts 2 filter and the Guice filter. However, we specified them in code instead of in the web.xml. We hardcoded struts.devMode to true, but you can easily see how we could make it true or false at runtime whereas that is impossible using a web.xml file.
You can also run Tomcat in embedded mode.
Thank you for your example. It helped me resolve a processing question using embedded java.
So how do you package your Application so that the WEB-INF directory gets included in the jar? Are you using maven?
Hi Norman,
I use Gradle at the moment for my build system. I’ve used Maven in the past, so I know it’s possible with Maven as well, but I’m less familiar with it. I think that either the war plugin or the assembly plugin’s jar-with-dependencies will work (but I’m not sure which :o)
-Ben
Thanks Ben. But it’s not trivial with maven to build a simple jar that includes everything. Especially when using spring.
Hey, I think your website might be having browser compatibility issues. When I look at your website in Safari, it looks fine but when opening in Internet Explorer, it has some overlapping. I just wanted to give you a quick heads up! Other then that, amazing blog!
Hi, Thanks for the example. I was actually looking for something similar. I do have a fully running application’s WAR file. It is Struts I and deploy to Tomcat. I would like to use Jetty with it. Basically, embedded or wrap the WAR file in Jetty.
Can you give me some advice or point me to some place where I can see some examples?
-Manny