Executable 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.

18 Responses to “Executable WARs with Jetty”

  1. Benjamin Muskalla says:

    Great stuff. Did you tried it with a RAP application yet?

  2. sud says:

    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.

  3. @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.

  4. Manuel, there is a WAR containing all the regular rap demos apps.

  5. Manuel Woelker says:

    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.

  6. Joel says:

    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.

  7. Manuel Woelker says:

    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

  8. Tim Perrett says:

    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.

  9. Manuel Woelker says:

    Good call, Tim. Fixed now. To be honest nowadays I don’t import anything, I just Ctrl-Shift-O it.

  10. Fernnado says:

    Maybe you should get this into the maven-jetty-plugin, as an option to publish an executable war file :)

  11. 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

  12. Krish Dasari says:

    Thanks for the tip. I got inspired and did a proof of concept to build an executable war using maven, grails and jetty.
    Notes is available @ krishnadasari.blogspot.com

  13. Note the executable-war-archetype , used as starting-point in the http://Mifos.org WAR, see http://goo.gl/nwZNE.

  14. Frederik Heick says:

    But how do you build it?
    What goal do you use and what dependencies is nessecary?

    Need a bit more info.

    So if I have Maven project which generates a war file.
    How do I make it executable with Jetty.?

  15. Jan Nielsen says:

    And how do you get support for JSP?

    I get this: “NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet”

    I have no idea of how to pass in the option, like this: $ java -jar jetty.jar OPTIONS=Server,jsp from
    http://manolocarrasco.blogspot.com/2009/09/tip-enabling-jsp-support-in-jetty700.html

  16. Paolo Milani says:

    I was doing this myself, as I was also inspired by Hudson/Jenkins.
    It seems the only way to support loading via “java -jar” requires to put the main .class and its dependencies in the “root” of the WAR, as it needs to be found via “Main-Class” attribute in MANIFEST.MF.
    I can’t get over the fact that sorting out the package structure is hacky.

    If anybody knows a different solution, please share!

    Anyway, the getProtectionDomain() trick is pretty neat.

  17. U Wieske says:

    Paolo,

    I have the same thoughts as you, about the “hacky” part. Have you already found another alternative for the aforementioned solution?
    I keep on getting the same references to the “Start” example solution on Internet.

    I wonder…. can these alien resources (classes in the root of this webapp) be served as response of a HTTP request? ….. :-/

  18. Paolo Milani says:

    In short, I lost the WAR — but won the battle ;)
    The only benefit of packaging a WAR in such a configuration is to build a single artifact that supports 2 different environments.
    More precisely a WAR is a particularly structured package that is understood by a standard JEE servlet container.
    We don’t need to support a servlet container anymore as we are migrating this app out of a JBoss.
    In the case of running an embedded Jetty server, you can get away much more easily by creating a “uber-jar”.
    I used the maven-shade-plugin for that, I found it easier and more controllable than the assembly plugin or onejar.

    Hope this gives you some ideas,
    cheers

18 responses so far

Written by . Published in Categories: Planet Eclipse