Export maven war artifact as runnable jetty package


Today I will show you a way to export a <packaging>war</packaging> artifact as a runnable windows application.

The ingredients are:

  • maven war artifact (i.e. our web application)
  • embedded Jetty

A minimal web application’s pom looks like this:

<?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>de.ahoehma</groupId>
  <artifactId>dummy-webapp</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>war</packaging>
</project>

Now we add some components to the artifact …

1. add the following profile to the pom.xml:

<profiles>
   <profile>
      <id>jetty-offline</id>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2-beta-5</version>
            <configuration>
              <finalName>offline-dummy-webapp-${project.version}</finalName>
              <attach>false</attach>
              <descriptors>
                <descriptor>src/assembly/jetty-offline.xml</descriptor>
              </descriptors>
            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <!-- logging ... -->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.1.1</version>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.15</version>
          <scope>runtime</scope>
        </dependency>
        <!-- embedded jetty -->
        <dependency>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <dependency>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>start</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <dependency>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-util</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <dependency>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jsp-2.1-jetty</artifactId>
          <version>${jetty.version}</version>
        </dependency>
      </dependencies>
      <properties>
          <jetty.version>6.1.23</jetty.version>
      </properties>
    </profile>
</profiles>

2. the assembly descriptor for src/assembly/jetty-offline is here:

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">

  <formats>
    <format>dir</format>
  </formats>
  
  <dependencySets>
    <dependencySet>
      <!-- unpack the webapp as root application -->
      <scope>runtime</scope>
      <unpack>true</unpack>
      <outputDirectory>webapps/root/</outputDirectory>
      <includes>
        <include>de.ahoehma:dummy-webapp:war</include>
      </includes>
    </dependencySet>
    <dependencySet>
      <unpack>false</unpack>
      <outputDirectory>lib</outputDirectory>
      <useTransitiveFiltering>true</useTransitiveFiltering>
      <useStrictFiltering>true</useStrictFiltering>
      <includes>
        <include>org.mortbay.jetty:jetty</include>
        <include>org.mortbay.jetty:jetty-util</include>
        <include>org.mortbay.jetty:start</include>
        <include>org.mortbay.jetty:jsp-2.1-jetty</include>
        <include>commons-logging:commons-logging</include>
        <include>log4j:log4j</include>
      </includes>
    </dependencySet>
  </dependencySets>

  <fileSets>
    <fileSet>
      <directory>src/jetty/bin</directory>
      <outputDirectory>bin/</outputDirectory>
      <filtered>false</filtered>
    </fileSet>
    <fileSet>
      <directory>src/jetty/resources</directory>
      <outputDirectory>etc/</outputDirectory>
      <filtered>false</filtered>
    </fileSet>
  </fileSets>
  
</assembly>

See maven-assembly-plugin for more options …

3. src/jetty/bin contains a windows batch file:

 @echo off
 @set JVM_OPTS=-XX:MaxPermSize=256m -XX:PermSize=128m -Xms128m -Xmx512m
 (cd .. && java %JVM_OPTS% -jar lib/start-6.1.23.jar)

4. and at least the src/jetty/resources contains the file jetty.xml:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.Server">
    <Set name="ThreadPool">
      <New class="org.mortbay.thread.BoundedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">250</Set>
        <Set name="lowThreads">25</Set>
      </New>
    </Set>
    <Call name="addConnector">
      <Arg>
          <New class="org.mortbay.jetty.nio.SelectChannelConnector">
            <Set name="host"><SystemProperty name="jetty.host" default="localhost"/></Set>
            <Set name="port"><SystemProperty name="jetty.port" default="1976"/></Set>
            <Set name="maxIdleTime">30000</Set>
            <Set name="Acceptors">2</Set>
            <Set name="statsOn">false</Set>
            <Set name="confidentialPort">8442</Set>
      	    <Set name="lowResourcesConnections">5000</Set>
      	    <Set name="lowResourcesMaxIdleTime">5000</Set>
          </New>
      </Arg>
    </Call>
    <Set name="handler">
      <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
        <Set name="handlers">
         <Array type="org.mortbay.jetty.Handler">
           <Item>
             <New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
           </Item>
           <Item>
             <New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
           </Item>
         </Array>
        </Set>
      </New>
    </Set>
    <Call name="addLifeCycle">
      <Arg>
        <New class="org.mortbay.jetty.deployer.ContextDeployer">
          <Set name="contexts"><Ref id="Contexts"/></Set>
          <Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>
          <Set name="scanInterval">1</Set>
        </New>
      </Arg>
    </Call>
    <Call name="addLifeCycle">
      <Arg>
        <New class="org.mortbay.jetty.deployer.WebAppDeployer">
          <Set name="contexts"><Ref id="Contexts"/></Set>
          <Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps</Set>
      	  <Set name="parentLoaderPriority">false</Set>
      	  <Set name="extract">true</Set>
      	  <Set name="allowDuplicates">false</Set>
        </New>
      </Arg>
    </Call>
    <Set name="stopAtShutdown">true</Set>
    <Set name="sendServerVersion">true</Set>
    <Set name="sendDateHeader">true</Set>
    <Set name="gracefulShutdown">1000</Set>
</Configure>

Now we are able to build a „offline version“ of our web application:

 mvn package -Pjetty-offline

The result will be a directory target\distribution\offline-dummy-webapp-1.0.0-SNAPSHOT with the structure:

 bin/
    jetty_run.bar
 etc/
    jetty.xml
 lib/
    log4j-1.2.15.jar
    commons-logging-1.1.1.jar    
    servlet-api-2.5-20081211.jar
    start-6.1.23.jar
    jetty-6.1.23.jar
    jetty-util-6.1.23.jar
    ant-1.6.5.jar
    core-3.1.1.jar
    ecj-3.5.1.jar
    jsp-2.1-jetty-6.1.23.jar
    jsp-2.1-glassfish-2.1.v20091210.jar
    jsp-api-2.1-glassfish-2.1.v20091210.jar
 webapps/
    root/
       index.html
       css/
       images/
       META-INF/
       pages/
       WEB-INF/
       ...

To run the web application start the jetty_run.bat (i.e. open the dir with the explorer and double click the bat-file).

That’s it 😀

This article was the first part if the tutorial … in the second part I will show you how to build a windows exe package with a runnable web application inside …