on Oct 2nd, 2009Executable WARs with Jetty
Today I want to talk about one of the younger members in the Eclipse family: Jetty. It is great to have such an interesting project on board and it is yet another example of how Eclipse has become more than just an IDE.
What I wanted to with jetty was to create an executable, standalone and self-contained WAR. I first encountered this concept in Hudson. The hudson.war contains an embedded Winstone servlet container, which makes it possible to run the application by executing
java -jar hudson.war
This makes test driving the application really simple. The idea was to do the same with Jetty. Embedding the Jetty runtime in the war proved to be the easy part, as it was just a matter of declaring the jetty dependencies in the maven pom.xml.
The tricky part was telling jetty where to find the war-file to serve. My first try was to hardcode the filename, but that left a foul aftertaste. Finding a solution took quite some time, which is why I am posting this for future reference. This is the Main-Class used to bootstrap Jetty (adapted from the Wicket quickstart archetype):
import org.mortbay.jetty.Connector; import org.mortbay.jetty.Server; import org.mortbay.jetty.bio.SocketConnector; import org.mortbay.jetty.webapp.WebAppContext; public class Start { public static void main(String[] args) throws Exception { Server server = new Server(); SocketConnector connector = new SocketConnector(); // Set some timeout options to make debugging easier. connector.setMaxIdleTime(1000 * 60 * 60); connector.setSoLingerTime(-1); connector.setPort(8080); server.setConnectors(new Connector[] { connector }); WebAppContext context = new WebAppContext(); context.setServer(server); context.setContextPath("/"); ProtectionDomain protectionDomain = Start.class.getProtectionDomain(); URL location = protectionDomain.getCodeSource().getLocation(); context.setWar(location.toExternalForm()); server.addHandler(context); try { server.start(); System.in.read(); server.stop(); server.join(); } catch (Exception e) { e.printStackTrace(); System.exit(100); } } }
The interesting bit is the getProtectionDomain()/getCodeSource() part, which tells us the location of the war-file. That’s all there is to it. Presto, executable web-application powered by Jetty in jar.
Edit: Added the import statements as per Tim’s suggestion.
Related posts:

Great stuff. Did you tried it with a RAP application yet?
This is interesting. I’m curious to see what the same code would like for embedded glassfish. I remember seeing it somewhere and it may have been even simpler.
@Benny: Haven’t tried it yet, mostly because I couldn’t find a premade war, and I didn’t want to go through the hassle of creating one myself. If you could provide me with a hello-world RAP WAR (or point me to one) I’d be happy to try that out.
@sud: glassfish might be option too. Jetty is still fairly light-weight. I don’t know any specifics but it would seem as if the overhead for glassfish would be a lot bigger (the glassfish installer weighs in at around 50 MB). There is an embedded glassfish project for that purpose, but the JAR still weighs in at around 17MB. So depending on your definition of lightweight this may not be an option.
Manuel, there is a WAR containing all the regular rap demos apps.
So it was right under my nose all along.
I tried mashing up the demo war and Jetty and I can report that it works flawlessly. It adds about 3MB to the file size, so not too bad. Might be worth considering for small demos and such.
Thx for the info, I was looking to do the same thing. But i can’t make it runnable like hudson. When executing my war with “java -jar myWar.war”, I always get the following exception : Exception in thread “main” java.lang.NoClassDefFoundError: org/mortbay/jetty/Connector
Could you tell me how you configured the manifest file so it worked?
Currently, i setted my “Main” class in the root of the jar, just like hudson and configured the manifest to use it. But jetty’s jar is in WEB-INF\lib\ unlike winstone in hudson that is in the root.
I tried to set an explicit classpath in the manifest without any success.
If you could provide the layout of your packaged WAR with the manifest you are using, it would really be appreciated.
Joel, your MANIFEST.MF is probably okay, but I don’t think plain Java supports jars-in-jars (or jars-in-wars in this case). I simply have the jetty classes right along side everything else in the war. So the top level in the war looks like this:
META-INF/
WEB-INF/
org/
javax/
Start.class
The manifest is in META-INF, the web-app itself in WEB-INF, Jetty resides in org/mortbay/jetty, the servlet API is under javax/servlet and the Start.class is referenced in the manifest. I used Jetty 6.1.17 [1], unpacked all the jars from the lib directory and then added both the org and the javax directories to the war, followed by Start.class and the META-INF/ folder with the manifest.
Hope that helps, good luck.
[1] http://dist.codehaus.org/jetty/jetty-6.1.17/jetty-6.1.17.zip
Hey Manuel,
This is great stuff – although, you really need to include the import statements in your code snippet so people know where those classes are coming from as its not clear.
Good call, Tim. Fixed now. To be honest nowadays I don’t import anything, I just Ctrl-Shift-O it.
Maybe you should get this into the maven-jetty-plugin, as an option to publish an executable war file
Thanks for the tip, probably saved me a lot of time
Used your example as the base for a gradle script that takes a war and “jettyfies” it. Might be interesting to someone: http://bit.ly/standalone-war