Jetty hardening

Hardening may be a bit of stretch here, so before you spent your time with the post, I’ll tell you what we’re going to do here:

  • Disable directory browsing (definitely security hole) in the web application context.
  • Disable default Jetty error messages – both in application context and out of it (if you’re not running application in the root context).
  • Remove Jetty version response header.
  • And a little shutdown hook that helps your application lifecycle in case of unexpected process termination (covers break/ctrl+C, not kill -9 obviously :-)).

This all applies to Jetty 9.2.x, I’m pretty sure these things change slightly between major Jetty versions, so you may need to adjust it for versions 8 or 7.

This is a compilation of some research on the internet and actual Jetty debugging, applied to our Spring based web application run under Jetty (and wrapped with Launch4J) and if you know how to do things better I’ll gladly hear about it in comments of course. It is also loose continuation of our previous parts:

So, let’s see some code!

The result

Ok, maybe not the best story-telling, but let’s see the actual result here first. I left also lines with logging, we can argue about log levels, but that’s not the point here. Because it’s a longer listing with all the features from previous post, I highlighted the lines that are related to today’s post:

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.ProtectionDomain;

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.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Port is customizable using -Dport=8181 - default is 8080.
 * Application context is customizable using -Dcontext=xxx - default is "". Initial slash is
 * always prepended internally after any leading or trailing slashes (/) are discarded from the provided value,
 * so both -Dcontext= and -Dcontext=/ define root context.
 */
public class RestMain {

    private static final Logger log = LoggerFactory.getLogger(RestMain.class);

    public static void main(String[] args) throws Exception {
        int port = Integer.parseInt(System.getProperty("port", "8080"));
        String contextPath = System.getProperty("context", "");

        log.debug("Going to start web server on port {} with context path {}", port, contextPath);
        Server server = new Server(port);
        disableServerVersionHeader();

        WebAppContext context = new WebAppContext();
        context.setServer(server);
        context.setContextPath('/' + contextPath);
        context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
        context.setErrorHandler(new ErrorHandler());

        ProtectionDomain protectionDomain = RestMain.class.getProtectionDomain();
        String warPath = protectionDomain.getCodeSource().getLocation().toExternalForm();
        if (warPath.toLowerCase().endsWith(".exe")) {
            warPath = prepareWarPathFromExe(warPath, "WEB-INF");
        } // else we assume dir or jar/war
        context.setWar(warPath);
        server.setHandler(context);
        log.debug("WebAppContext set for server with location {}", warPath);

        // default error handler for resources out of "context" scope
        server.addBean(new ErrorHandler());

        server.start();
        if (!context.isAvailable()) {
            //noinspection ThrowableResultOfMethodCallIgnored
            log.error("Application did NOT started properly: {}", context.getUnavailableException().toString());
            server.stop();
        } else if (context.getWebInf() == null) {
            log.error("Application was NOT FOUND");
            server.stop();
        } else {
            log.debug("Application READY");
            addJettyShutdownHook(server);
        }
        server.join();
        log.debug("Exiting application");
    }

    private static void addJettyShutdownHook(final Server server) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    log.debug("Exiting application (shutdown hook)");
                    server.stop();
                } catch (Exception e) {
                    log.warn("Exception during server stop in shutdown hook", e);
                }
            }
        });
    }

    private static String prepareWarPathFromExe(String pathToExe, String... prefixes) throws IOException {
        Path tmpWarDir = Files.createTempDirectory("restmod");
        final String warPath = tmpWarDir.toString();
        log.debug("Extracting WAR from EXE into {}, prefixes {}", warPath, prefixes);

        WarExploder warExploder = new WarExploder(pathToExe, warPath);
        warExploder.explode(prefixes);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    deleteRecursive(Paths.get(warPath));
                    log.debug("Temporary WAR directory deleted");
                } catch (IOException e) {
                    log.warn("Problems with deleting temporary directory", e);
                }
            }
        });
        return warPath;
    }

    private static void deleteRecursive(Path dir) throws IOException {
        if (Files.isDirectory(dir)) {
            try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir)) {
                for (Path path : directoryStream) {
                    deleteRecursive(path);
                }
            }
        }
        Files.delete(dir);
    }

    private void disableServerVersionHeader() {
        for (Connector y : server.getConnectors()) {
            y.getConnectionFactories().stream()
                .filter(cf -> cf instanceof HttpConnectionFactory)
                .forEach(cf -> ((HttpConnectionFactory) cf)
                    .getHttpConfiguration().setSendServerVersion(false));
        }
    }

    /**
     * Dummy error handler that disables any error pages or jetty related messages and returns our
     * ERROR status JSON with plain HTTP status instead. All original error messages (from our code) are preserved
     * as they are not handled by this code.
     */
    static class ErrorHandler extends ErrorPageErrorHandler {
        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.getWriter()
                .append("{\"status\":\"ERROR\",\"message\":\"HTTP ")
                .append(String.valueOf(response.getStatus()))
                .append("\"}");
        }
    }
}

Now we can walk through these parts.

Directory browsing

This was the easy part after we accidently found out it is allowed. Just add this line to your WebAppContext:

context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");

We are running REST-like API under some context path and if we comment out this line, Jetty will nicely allow us to browse the directory (WEB-INF included). This line ensures that HTTP 403 Forbidden will be returned instead. How this status is treated…

Error handling in your application

There are errors you can treat in your application – these are not problem. And then there are cases that somehow slip out, there is no reasonable way how to intercept them and server displays some ugly error for it, introducing itself to the user completely. If I run application on http://localhost:8080/xxx and I hit that URL, I get the following output:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 404 Not Found</title>
</head>
<body>

<h2>HTTP ERROR 404</h2>




Problem accessing /finrisk/easd. Reason:


<pre>    Not Found</pre>
<hr>

<i><small>Powered by Jetty://</small></i><hr/>

</body>
</html>

That is not bad, but I’d like short JSON we use for error messages. This can be customized in web.xml:

<!-- somewhere at the end of web.xml →
<error-page>
    <location>/api/0.1/error</location>
</error-page>

This will point the application to our error resource and this is returned:

{"status":"ERROR","message":"HTTP 404"}

Alternatively we can achieve the same with custom Jetty ErrorHandler as we defined it at the end of our JettyMain class:

context.setErrorHandler(new ErrorHandler());
...
static class ErrorHandler extends ErrorPageErrorHandler {
  @Override
  public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.getWriter()
      .append("{\"status\":\"ERROR\",\"message\":\"HTTP ")
      .append(String.valueOf(response.getStatus()))
      .append("\"}");
  }
}

This effectively replaces your web.xml definition (if present) and if you debug your application you can confirm that with a breakpoint that would be reached without this jetty line and will not be when it’s present.

How about URLs out of webapp context?

Let’s now access some URL out of our application – like http://localhost:8080/yy – this will result in very similar default Jetty error page like we’ve seen already:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 404 </title>
</head>
<body>


<h2>HTTP ERROR: 404</h2>




Problem accessing /. Reason:


<pre>    Not Found</pre>
<hr />

<i><small>Powered by Jetty://</small></i>
</body>
</html>

This is also easy to fix, because we can reuse our ErrorHandler – just add this line for your Jetty Server instance:

server.addBean(new ErrorHandler());

But are we really done?

Not so fast…

The trouble is that error handler (or error resource configured in web.xml) is only used when Jetty (or any servlet container) thinks there was an error. If you handled the exception some other way, then this ErrorHandler is not used – whatever HTTP status you send.

We use Jersey as our REST API provider where you can register ExceptionMapper for particular exception type (and all its subtypes). When this is triggered and you populate javax.ws.rs.core.Response with the output and set HTTP status, it will not trigger this error page. We handled the error once, no reason to do it twice.

But in case of Jersey there are exception mappers for JSON parse errors and these may leak some information. Let’s try any URL that expects JSON in POST with unpaired curly brace and you’ll get this error (going around your custom ErrorHandler or error page):

Unexpected end-of-input: expected close marker for OBJECT (from [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@1986598; line: 1, column: 0])
 at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@1986598; line: 1, column: 3]

This is not acceptable, but in this case you have to fight the framework (Jersey) to unregister internal mappers and register yours to get back on track. But obviously, this is out of scope of this blog post. Just remember that we’re covering only unhandled errors and any other error/exception handlers has to be checked too.

Response header with Jetty version

If you examine the communication between web browser and server, you can notice, that Jetty still reveals itself in the response header. While in previous version it was a matter of a single-line setter – you can’t stop the progress – it’s now a matter of more lines.

I take no credit for the solution as I found it on StackOverflow, except I obscured it with Java 8 syntax in case you use older Java (find the original in the linked answer). All the magic happens in method disableServerVersionHeader.

Shutdown hook

Finally something straightforward and not Java EE at all. When your Jetty server starts and application (Java process) gets terminated somehow, it will not stop the Jetty server in a graceful manner. With it goes down our Spring application – and if you have components with @PreDestroy, these method will likely not get run.

To do better than this we utilize Java’s shutdown hooks. The code goes like this:

// after Jetty starts OK with our app running
addJettyShutdownHook(server);
...
private static void addJettyShutdownHook(final Server server) {
  Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
      try {
        log.debug("Exiting application (shutdown hook)");
        server.stop();
      } catch (Exception e) {
        log.warn("Exception during server stop in shutdown hook", e);
      }
    }
  });
}

All we have to do is call server.stop(). Would finally block in the main method do the same? Probably – I’m too tired to try… but mainly – shutdown hook communicates “I’ll be run when the process goes down” much better I think.

Finally

There’s a lot more to do with Jetty – and I don’t know most of it. I’m not doing any SSL here or Jetty based authentication, but aforementioned little patches should help it a lot. In case of error handler vs error page within the webapp context – it’s your choice probably. If you don’t have error page yet, then it is the easy one. But unless you run the application on the root context (/) you definitely want to shut up Jetty’s default messages in production. Finally – shutdown hook will help the webapp going down nicely. This is twice so important if you have another container inside (like Spring). In any case, it makes our applications graceful, right? Who doesn’t want to have graceful applications? 🙂

Advertisements

Jetty with self-extracting WAR from Launch4J EXE

In my previous post I was hacking Tomcat and Jetty with Launch4J – Jetty eventually won as it was willing to read JAR as WAR (not so picky about file extension as Tomcat was) and find WEB-INF/web.xml there without problems.

Yesterday I decided to go on with my quest and populate temporary WAR directory from my classpath programmatically – which would actually get Tomcat (or any other embedded container reading exploded WARs from disk) back into game. We will utilize Java 7 NIO2 classes, so if you’re stuck with Java 6 you have to adjust parts of the solution.

POM simplification

We will stick with Jetty for other reasons, but it will provide some flexibility there as well – now we can wrap JAR into EXE which we carefully avoided previously with plugin options (plugin was com.akathist.maven.plugins.launch4j:launch4j-maven-plugin, see the previous post for the listings):

  • <jar>${project.artifactId}-${project.version}.jar</jar>
  • <dontWrapJar>true</dontWrapJar>

These overrode parent POM’s defaults:

  • <jar>${project.build.directory}/${project.artifactId}-${project.version}.jar</jar>
  • <dontWrapJar>false</dontWrapJar>

So let’s minimise the module’s POM – without changing parent’s one we just mention both plugins we need – launch4j to get EXE and dependency plugin to populate directory with dependencies for us:

  <profiles>
    <profile>
      <id>exe-build</id>
      <build>
        <plugins>
          <plugin>
            <groupId>com.akathist.maven.plugins.launch4j</groupId>
            <artifactId>launch4j-maven-plugin</artifactId>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

Neat – my EXE module does not differ from other EXE modules (those without containers) anymore! Let’s code now, yeah… I mean not in XML.

Extracting web.xml from classpath

Using our previous bootstrap code, we just want to check whether our warPath is EXE file or not. If not, we can leave it that way, Jetty will read from JAR/WAR or even target/classes (especially handy during development). If it is EXE, however, we want to get the WAR stuff out. Explode it ourselves:

int port = Integer.parseInt(System.getProperty("port", "8080"));
String contextPath = System.getProperty("context", "app");

Server server = new Server(port);
WebAppContext context = new WebAppContext();
context.setServer(server);
context.setContextPath('/' + contextPath);

ProtectionDomain protectionDomain = RestMain.class.getProtectionDomain();
String warPath = protectionDomain.getCodeSource().getLocation().toExternalForm();
if (warPath.toLowerCase().endsWith(".exe")) {
  warPath = prepareWarPathFromExe(protectionDomain);
} // else we assume dir or jar/war
context.setWar(warPath);
server.setHandler(context);

server.start();

if (!context.isAvailable() || context.getWebInf() == null) {
  server.stop();
}
server.join();

Ok, that was easy – tiny change in the original code. Now the hard part – but first we just extract a single file – web.xml.

  private static String prepareWarPathFromExe(ProtectionDomain protectionDomain) throws IOException {
      String warPath = temporaryWar(protectionDomain.getClassLoader());
      log.debug("Extracting WAR from EXE into: " + warPath);
      final String finalWarPath = warPath;
      Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
          try {
            deleteRecursive(Paths.get(finalWarPath));
            log.debug("Temporary WAR directory deleted");
          } catch (IOException e) {
            log.warn("Problems with deleting temporary directory", e);
          }
        }
      });
      return warPath;
    }

    private static String temporaryWar(ClassLoader classLoader) throws IOException {
      Path tmpWarDir = Files.createTempDirectory("restmod");
      Path webInf = tmpWarDir.resolve("WEB-INF");
      Files.createDirectory(webInf);
      Files.copy(classLoader.getResourceAsStream("WEB-INF/web.xml"), webInf.resolve("web.xml"));
      return tmpWarDir.toString();
    }

    private static void deleteRecursive(Path dir) throws IOException {
      if (Files.isDirectory(dir)) {
        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir)) {
          for (Path path : directoryStream) {
            deleteRecursive(path);
          }
        }
      }
      Files.delete(dir);
    }

I think the code is easy to follow for most of the part. Shutdown hook deletes the temporary directory. We work with ClassLoader to get our resources, etc. If all you need is WEB-INF/web.xml, you can stop here. But this is far from flexible in case you have JSPs and other resources to extract. So let’s try to extract everything starting with specified strings.

Extracting more

I don’t know whether there is some reasonable way to “crawl” through classpath resources, however it is not what we need, actually. We want to check the EXE file and treat it as a JAR. While Jetty does not like context set to this EXE path (not even if you use URL starting with jar:file:/ and ending with !/), it is still perfectly valid JAR file.

First I wanted to use one of my ancient solutions inspired by Stripes framework. This checks JARs on the classpath, and opens their files as JarInputStream. This didn’t seem to work. However I found suggested Spring solution for reading resources using patterns:

PathMatchingResourcePatternResolver resolver =
  new PathMatchingResourcePatternResolver(protectionDomain.getClassLoader());
Resource[] resources = resolver.getResources("classpath*:WEB-INF/**");
// then copy the resources where necessary

And this worked and found resources in my EXE file too. So I dag a bit deeper, found the Spring’s class PathMatchingResourcePatternResolver and the method doFindPathMatchingJarResources – and I was back on track.

First we will adjust our calling statement from main method, because we’re leaving waters of classpath (taken from ProtectionDomain). And we introduce our prefixes from which we want to extract (META-INF is just an example, choose yours):

warPath = prepareWarPathFromExe(warPath, "WEB-INF", "META");

The rest of the main method stays untouched. Now the new body of the prepareWarPathFromExe method:

    private static String prepareWarPathFromExe(String pathToExe, String... prefixes) throws IOException {
      Path tmpWarDir = Files.createTempDirectory("restmod");
      final String warPath = tmpWarDir.toString();
      log.debug("Extracting WAR from EXE into {}, prefixes {}", warPath, prefixes);
      WarExploder warExploder = new WarExploder(pathToExe, warPath);
      warExploder.explode(prefixes);
      Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
          try {
            deleteRecursive(Paths.get(warPath));
            log.debug("Temporary WAR directory deleted");
          } catch (IOException e) {
            log.warn("Problems with deleting temporary directory", e);
          }
        }
      });
      return warPath;
    }

Recursive delete stays the same. I put WAR exploding into separate class so I can put both paths into fields and don’t drag them through parameters. (And I’d hate to put them into static variables in my main class too.) Here it is:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * Extracts files from JAR to specified directory. Extraction can be called multiple times for various set of prefixes.
 * Prefix matches if the JAR entry name starts with it, that is "META" matches META-INF and anything under.
 */
class WarExploder {
    private final File srcJarFile;
    private final Path explodedDir;

    WarExploder(String jarFilePath, String explodedDir) {
      if (jarFilePath.startsWith("file:/")) {
        jarFilePath = jarFilePath.substring("file:/".length());
      }
      srcJarFile = new File(jarFilePath);
      this.explodedDir = Paths.get(explodedDir);
    }

    void explode(String... prefixes) throws IOException {
      try (JarFile jarFile = new JarFile(srcJarFile)) {
        List<JarEntry> entriesToExtract = jarFile.stream()
          .filter(e -> Arrays.stream(prefixes).anyMatch(e.getName()::startsWith))
          .collect(Collectors.toList());

        // throws checked exception, hence the for-each
        for (JarEntry jarEntry : entriesToExtract) {
          extractIfMatching(jarFile, jarEntry);
        }
      }
    }

    private void extractIfMatching(JarFile jarFile, JarEntry jarEntry) throws IOException {
      String name = jarEntry.getName();
      Path targetPath = explodedDir.resolve(name);
      if (jarEntry.isDirectory()) {
        Files.createDirectory(targetPath);
      } else {
        Files.copy(jarFile.getInputStream(jarEntry), targetPath);
      }
    }
}

This time I used a bit of streams too, but there should be no problem to switch it to Java 7, maybe a bit more problem to use Java 6 – but if you’re that far in the past, then you rather use some Apache libs to copy files too.

Exploder doesn’t log, everything is delegated (and exception propagated) to the main class.

Conclusion

It wasn’t that hard after all. Although the solution is pure JDK after all, I have to thank Spring developers for their incredible work and inspiration (not just here and now). In cases like these you also can feel the pain of developers still stuck with pre-7 Java, as NIO 2 does miracles with Files and Paths (finally!). It also wouldn’t be possible without JDK working with JARs so easily. Actually if I had headed into getResourcesAsStream in URLClassLoader, I’d have found the proper way of working with JAR.

Originally I thought JarURLConnection was the solution, but the real key was using JarFile instead of JarInputStream (that works perfectly OK in other circumstances). You can create JarFile using JarURLConnection or just plain File. Having the file lying around on the disk, I felt that File should suffice – and it did.

There is also related StackOverflow answer (and probably more).

Next time we will talk about “hardening” our Jetty application, so that it produces our error messages instead of the default ones (not to mention that directory browsing is on by default too!) – but that will be much shorter than today’s post. 🙂

Launch4j and embedded web container

Embedded web container is nice. Of course you’ll lose some benefits of a big container, but you’ll get something else. Sometimes it’s faster startup. And sometimes it’s ability to wrap your Java web application into executable.

In our system we have multiple modules and most of them are executables on Windows machine (not my preference anyway ;-)). There is some control console that can start them, kill them, etc. And our Tomcat kinda stuck out of this exe family. Before I could start Launch4j-ize our WAR I have to turn the thing around and embed the container into JAR. Something I did many times before with Jetty – although mostly only for development purposes with our exploded WAR somewhere in target directory.

Embedding web container

First step was to run some main class and get to a state when my application is accessible on some port+context – just like it would be after normal deployment. Because we were friends with Tomcat at the moment, I went for this option.

Code was easy, there are blogs you can find – I used this one with minor adjustments and with mere two tomcat artifacts (tomcat-embed-core and tomcat-embed-logging-juli) I was up and running (Tomcat 8.0.15).

I ran into couple of problems however:

  • Tomcat logging – I know it’s not Tomcat’s fault that Sun made such a horrible decision with JUL and I understand when someone uses it (portability is probably the only reason). I tried to use org.slf4j:jul-to-slf4j to little/no avail, but I didn’t give it so much time for more serious problems.
  • I was generally unhappy with the speed. It took maybe 10s of silence until my application showed its first log. No need for concrete numbers – maybe it can be adjusted, but when I compared it with expectations (and other containers – full-blown or embedded) the pause before actually starting the application was just too long.
  • The main blow however came from different direction. This is my main trouble with all these embedded containers – they kinda expect the WAR to be somewhere on disk (exploded or packed, doesn’t matter). What if I want to run it from classpath? I have web.xml as a resource already there! It seems that this is common to all the containers I met – or this kind of webapp loading is not documented. Maybe it’s not even possible because of Java EE specification – I really don’t know. So you have to have WAR. Or do you?

So my embedded application is running, why am I complaining about the last point then? I want to run the application as Windows executable and I want to avoid messing with filesystem if possible.

When JAR and WAR unite

But this seems not possible. Let’s say I run EXE wrapper for JAR file. This can be either embedded in EXE file directly, or lying somewhere around it. How am I supposed to provide WAR? Tried options:

  • Launch4j created app.exe that used the content of separate app.jar. JAR contained WEB-INF/web.xml too, but classes were placed like in normal JAR. This works fine when exploded, because web.xml is used to configure the application and the rest is on the classpath already. But not when packaged as JAR. For one – embedded Tomcat will not accept JAR file because its extension is .jar and not .war! Whatever the reason for this is, it was showstopper for this option.
  • Let’s change packaging of my “app” artifact to war then. I had to override couple of configuration options for launch4j maven plugin because now I wasn’t so unified with other non-web-app modules (based on jar packaging). This brings problems that classes in WEB-INF/classes are not on classpath before the webapp goes up. And because my main class is in that war (don’t let me create another Maven module for that class :-)) it is not found. I can meddle with my POM now to get the main class (with package structure) to root of the WAR file (working as JAR at that moment). This would probably double the size of the POM file (easy things made Maven way, you know), but I just gave up here.
  • Back to JAR packaging and let’s use something that can read WARs with “.jar” extension. 🙂 And so we get to Jetty.

To be fair, these are far from all the options. Just like jenkins.war (although that one uses Jetty instead of Tomcat) it is possible to do it with Tomcat after all – just leave JAR packaging and rename the resulting file (again too many lines for such a simple thing). This leads to further changes in launch4j configuration too however + we’re still stuck with slow start. It’s simply time to try something else. 🙂

From Tomcat to Jetty

I was friendly with Jetty for the last four years. Not a master of this cute pet- after all it’s actually more complex than people are generally aware. It’s typically one of the tools nobody cares to study, “because I just use it during development”. Well here I am and I don’t want to use it merely for development.

Thinking about how Jenkins is run, first I try to solve this part. Answer was found in the post Executable WARs with Jetty (or this SO question that references it too). I’ll copy my version of final code:

public static void main(String[] args) throws Exception {
    int port = Integer.parseInt(System.getProperty("port", "8080"));
    String contextPath = System.getProperty("context", "app");

    Server server = new Server(port);
    WebAppContext context = new WebAppContext();
    context.setServer(server);
    context.setContextPath('/' + contextPath);

    ProtectionDomain protectionDomain = RestMain.class.getProtectionDomain();
    String warPath = protectionDomain.getCodeSource().getLocation().toExternalForm();
    context.setWar(warPath);
    server.setHandler(context);

    server.start();
    if (!context.isAvailable() || context.getWebInf() == null) {
     server.stop();
    }
    server.join();
}

I skipped all my logging and imports (those from jetty are obvious after all). Most interesting part here is the one setting the warPath. This actually works equally great for exploded wars (during development) and for JARs lying next to executable wrapper.

Obviously, not even Jetty is reading the WAR part from classpath. And it uses some temporary directory too, just less obvious than Tomcat’s tomcat.8080 placed in working directory. But Jetty can tread JAR as WAR when told to.

How about JAR wrapped in executable?

This is in fact how Launch4j creates our exe files by default (option dontWrapJar is false). Maybe it’s time to show our plugin setup for Launch4j for your convenience. Note that you need both launch4j-maven-plugin and maven-dependency-plugin. This is the default setup from our parent POM (it’s in build/plugin-management/plugins section, in our case further nested in profiles/profile, because we don’t create EXE files by default on our Linux based CI machine):

<plugin>
    <groupId>com.akathist.maven.plugins.launch4j</groupId>
    <artifactId>launch4j-maven-plugin</artifactId>
    <version>1.7.1</version>
    <executions>
        <execution>
            <id>l4j-clui</id>
            <phase>package</phase>
            <goals>
                <goal>launch4j</goal>
            </goals>
            <configuration>
                <headerType>console</headerType>
                <jar>${project.build.directory}/${project.artifactId}-${project.version}.jar</jar>
                <outfile>${project.build.directory}/${executable.name}.exe</outfile>
                <dontWrapJar>${launch4j.dontWrapJar}</dontWrapJar>
                <classPath>
                    <mainClass>${mainClass.name}</mainClass>
                    <preCp>dependency_libs/*.jar</preCp>
                </classPath>
                <icon>src/main/resources/${executable.name}.ico</icon>
                <versionInfo>
                    <fileVersion>1.0.0.0</fileVersion>
                    <txtFileVersion>${project.version}</txtFileVersion>
                    <fileDescription>${project.name}</fileDescription>
                    <copyright>...</copyright>
                    <productVersion>1.0.0.0</productVersion>
                    <txtProductVersion>1.0.0.0</txtProductVersion>
                    <productName>${project.name}</productName>
                    <companyName>...</companyName>
                    <internalName>...</internalName>
                    <originalFilename>${executable.name}.exe</originalFilename>
                </versionInfo>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.9</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/dependency_libs</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

I override our global config in my module’s POM like this (I’m mentioning maven-dependency-plugin too to trigger it):

<build>
    <plugins>
        <plugin>
            <groupId>com.akathist.maven.plugins.launch4j</groupId>
            <artifactId>launch4j-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>l4j-clui</id>
                    <configuration>
                        <jar>${project.artifactId}-${project.version}.jar</jar>
                        <dontWrapJar>true</dontWrapJar>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
        </plugin>
    </plugins>
</build>

There are many other ways how to do this – you can go for some uberjar solution, etc. Important thing here is that <jar> element here does not reference JAR to be included into EXE, but it must be relative path to JAR when the EXE is started. Meaning of this element is changed by dontWrapJar flag.

Do I need to do this? Isn’t it possible to use EXE as WAR? Sounds silly at first, but I was surprised to discover that you can “enter” the EXE in Total Commander using Ctrl+PgDn – just like any other archive. Obviously – it’s self-extracting archive! When you include your JAR into it, it is correctly identified as a location of the main class in the bootstrap code – but Jetty will silently ignore it. In fact, this is the reason for context.getWebInf() == null check in the bootstrap code.

Anyway we’re still much better here than with Tomcat. Startup is faster, file can be named with JAR extension, what more do we want?

Other options

Before we try to enhance our current solution, let’s talk about other options. But not for long, really. Originally I wanted to try Undertow because it just seems to be cool. After reading its documentation I realized that I’d have to do more than just show it some web.xml file to start the application for me.

How about JBoss’s WildFly then? It is full-blown AS and can be embedded! However I found no documentation how to embed it that was not related to Arquillian, that is testing. Too bad. I love WildFly otherwise.

Glassfish? Probably possible but at this stage I just decided to go for simpler web containers. If you have anything useful to this topic, or other embeddable containers, please, mention it in discussion (no registration required, BTW).

Get out of my classpath!

I’ll not go further with examples, just with one idea found during extensive browsing while I was hunting the solutions. So Jetty/Tomcat/any container wants WAR in the file – or exploded WAR somewhere on the disk. They all create some kind of temporary files… so why can’t I? My bootstrap code can read web.xml (which can in turn be placed wherever on the classpath, not just WEB-INF) and put it in some temporary directory (Files#createTempDirectory) into WEB-INF subdirectory. Then we can point our WAR path there and let any worthy embedded container do the rest! Of course – if you have more than just a web.xml (JSPs, static stuff) you have to do more work, but that doesn’t make it less possible.

You may want to avoid this process for development – but again, this is easy to detect (“if the location of the main class is within EXE then do this else just use the location directly”).

Conclusion

Creating application with embedded web containers is a bit more complicated when Java application is wrapped in EXE – but that is expected. Any way you package your application, however, the biggest problem is that you somehow have to get your WAR on the disk (or something your embedded container likes like a WAR). Using app.war and running it with java -jar app.war is probably most straightforward. However if you want to share libraries with other modules and avoid uberjars, and/or use exe wrappers, things get more and more complicated. Externalizing WAR content (without classes, those are on the classpath already) in the bootstrap code may be a solution.

There is one more class of problems if you use Spring as well. Imagine all your modules bootstrap Spring application context. But your web module is doing it differently – it bootstraps webapp somehow and Spring is configured in web.xml. This is far less flexible during development too, as you can’t easily swap @Configuration class defined in the web.xml (or XML config). You can “shadow” them from test classpath but that mostly sucks. But if you invert the process and bootstrap Spring first, then it doesn’t know about web application yet and god knows what happens (or not and should) to your Jersey resources, etc.

However, this is different story for a different day… and looking at the calendar, probably for a different year too! Merry Christmas and Happy New Year!

Starting with Wicket on IntelliJ IDEA

I’ve changed my job recently and went to another company to do more or less the same I did for 10 years (Java based information systems typically delivered through web browser) – but with completely different stack. I did JBoss Seam with JSF/Facelets, later we switched to GWT (still on top of the Seam), previously we used Struts (many years ago, but really hard to forget ;-)) and among these things we used EJB 2.1 (ouch!) and 3.0 (finally usable).

Now I’m learning Spring and Wicket – and it’s a lot of stuff to learn. Couple of cunning colleagues came up with interesting modeling framework on top of this stack (based on EMF) – so it’s even more stuff to learn now. But here the whole thing does make sense and I’m trying my best to beat the learning curve. And yes, I had to switch from Idea to Eclipse as well (soon rant #2 will follow ;-)).

But to test Wicket hands-on from the basics at home I decided to use Idea. Because one guide is just too old and others are hardly guides, I decided to write this one. It’s pretty simple actually because to start with Wicket is really easy (which is a big compliment to the framework). A few years ago I had to appreciate how JBoss Seam examples were written – they really worked even though the technology stack there is quite crazy. But then you forgot seam.properties in your first Hello World test and went crazy for a few days. Wicket is simpler. Of course, Seam is more than just the web framework – that’s why we used it under GWT although I would probably not use it if I hadn’t known it before really.

But back to the topic. Every recipe has to start with things we need:

  • Wicket 1.5 (or maybe 1.4, but we’re just so eager to use 1.5 that we’re testing that one) (link is for RC1, check if there is newer/more stable release!)
  • IntelliJ IDEA 10.0.2 Community Edition (or whatever similar, full edition, …)
  • Jetty 8.x (I mean, it works with M2 release, but you’ll probably download some stable 7.x :-))
  • Velocity 1.7 (needed for Wicket, and not bundled as Wicket kinda expects you to use Maven)
  • SLF4J 1.6.1 (the same reason)
  • Idea plugin WicketForge (install it directly from Idea’s available plugins)

Unzip Wicket, SLF4J, Velocit and Jetty to your lib directory, create libs for them in Idea (or one lib with all relevant JARs – your choice) and add these libs to your project. I have one testing project for various trials and experiments so I just added these libraries there. You can’t go wrong if you add all JARs from Wicket’s lib directory, Jetty’s lib directory, from SLF4J just add slf4j-api-1.6.1.jar and slf4j-jdk14-1.6.1.jar and finally velocity-1.7-dep.jar.

Technically we will just copy and paste this Hello World example. You can find nearly the same example in Wicket’s directory
...\src\wicket-examples\src\main\java\org\apache\wicket\examples\helloworld, but this one’s classes are derived from some common Example application classes. That said – you can go and inspire yourself in that directory, but when you drag classes from there you have to change their extends (at least for HelloWorld nothing more was required).

When you write it all, you have to build it, pack it or somehow prepare extended war and start your favourite server (as said on the example page), but we don’t want that. That’s where Jetty comes in. First check if you can compile it all. If yes, add this main method into the application class (actually it can be any other class, but why? :-)):

public static void main(String[] args) throws Exception {
      Server server = new Server();
      Connector connector = new SelectChannelConnector();
      connector.setPort(8080);
      connector.setHost("127.0.0.1");
      server.addConnector(connector);

      WebAppContext wac = new WebAppContext();
      wac.setContextPath("/");
      wac.setWar(".");
//    wac.setParentLoaderPriority(true);
      server.setHandler(wac);
      server.setStopAtShutdown(true);

      server.start();
}

Now you should have project that fits on one screen and looks like this:

Now compile the package (or the whole project, whatever suits you) and run the class with main method. Setup the runner so that the working directory points to the helloworld package (or fix the path to your WAR in code – up to you). You should have no problem with classes – but if you do, try to uncomment that line with setParentLoaderPriority. I think it saved my life on a different project, but funny enough – it doesn’t seem to do anything (be it true or false) in this case. It is somehow documented here – but it’s quite vague if you ask me.

But you will probably face another problem related to Velocity:

Caused by: org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'VM_global_library.vm'

While it’s easy to find many references where they say it’s rather no problem, if you go to http://localhost:8080 (program keeps running) you will probably get HTTP 503. I’m no Wicket/Velocity expert and I think it’s quite a shame this resource is wanted so hard – yet it’s not in the JAR or whenever. But you can copy it from Velocity’s ...\test\templates\VM_global_library.vm to your default package and “compile” it from there. To be able to “compile” it, go to Settings (Ctrl+Alt+S), Compiler and add “;?*.vm” (without quotes) at the end of Resource patterns.

Alternatively you just copy the VM file to the output directory yourself – find out where it is via Project Structure (Ctrl+Alt+Shift+S), Project, Project compiler output. Under that out directory you have to go on to production\all and there are classes from the default package – and that’s where should the VM file go too.

Now you should be ready to run the program again (Shift+F10 if you didn’t change the settings) and this time you should get Hello World!

OK – I know it’s nothing great and you can get there with Maven much faster, but right now you have Idea ready for more Wicket testing, you can extend your application and you don’t rely on Ant or Maven – just compile and run. And if you successfully installed WicketForge you have also basic tool support for switching between HTML template and component class (Alt+Shift+W) or if you are on the component ID, just press F4 (quite naturally). Orange colour in this case is good. It’s not red. 🙂

Happy Wicket testing to you all. Comment if you feel so and if you have anything to add. I’m still just a Wicket newbie and maybe you can shed some light on that Velocity problem or explain Jetty classloading better. Cheers.

I nearly forgot! Download my Idea project here – but you still have to setup those libraries. After that it’s just Shift+F10.