Webapp Runner – Apache Tomcat as a Dependency

John Simone, a fellow co-worker at Heroku, has created webapp-runner which provides an easy way to specify Tomcat as a dependency of your app and launch Tomcat. This is useful for making it simple to test your app locally but it also helps to avoid issues stemming from differences in runtime environments.

Here is how to use it from a Maven pom.xml build:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>hellojavawebapprunner</artifactId>
    <name>hellojavawebapprunner</name>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.github.jsimone</groupId>
            <artifactId>webapp-runner</artifactId>
            <version>7.0.22</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <webappDirectory>${project.build.directory}/${project.artifactId}</webappDirectory>
                    <warName>${project.artifactId}</warName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals><goal>copy-dependencies</goal></goals>
                        <configuration>
                            <includeArtifactIds>webapp-runner</includeArtifactIds>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Then just run the Maven build:

mvn package

And start up Tomcat using webapp-runner pointing to the exploded war:

java -jar target/dependency/webapp-runner-7.0.22.jar target/hellojavawebapprunner

Or you can point it to a war file:

java -jar target/dependency/webapp-runner-7.0.22.jar target/hellojavawebapprunner.war

Since this method still uses war packaging you can do the usual web app deployment in Eclipse or IntelliJ. But that means deploying to a different runtime than what is specified as a dependency. Since one goal of using the webapp-runner is runtime consistency it is better to launch the webapp-runner for local testing. To do that just use the “webapp.runner.launch.Main” class and give it “src/main/webapp” as an argument. Eclipse will include the webapp-runner jar in the launch classpath even though the scope is “provided”. In IntelliJ you need to either manually add the libraries to the runtime classpath or change the scope to “compile” (the default). But this has a side effect of copying the jars into the WEB-INF/lib directory. Maybe someone else knows of a better solution.

I’ve posted a simple example project on GitHub that uses the webapp-runner. Also checkout the webapp-runner project on GitHub for more details on how to use it. If you’d like to try this out on Heroku then you can easily deploy a copy using the java.herokuapp.com app that I created.

Let me know if you have any questions or comments. Thanks!