Jan Goyvaerts
Jan Goyvaerts

Reputation: 3023

Self-contained war file with Tomcat embedded?

Is there anyone who has succeeded in making a self-contained .war file using Tomcat 7 embedded ? With Maven that is.

I mean with "self-contained" that the war file can also be used at the command line as:

java -jar application.war

With which it should pick up the Main Class of META-INF/MANIFEST.MF and run the application with the provided embedded Tomcat 7.

I managed to make it run as such, but I can't seem to be able to package it into a .war file that does the same.

Anybody has a link to documentation of some sorts ?

TIA !!!

Jan

Adding an extract from the pom.xml :

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
    <configuration>
      <failOnMissingWebXml>false</failOnMissingWebXml>
      <archive>
        <manifest>
          <mainClass>EmbeddedMain</mainClass>
          <addClasspath>true</addClasspath>
          <classpathPrefix>WEB-INF/lib/</classpathPrefix>
        </manifest>
      </archive>
      <webResources>
        <resource>
          <directory>target/classes</directory>
        </resource>
      </webResources>
    </configuration>
  </plugin>

Where "EmbeddedMain" is the class containing the main() method. And although everything seems to be in its place, I'm still getting:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/catalina/LifecycleListener
Caused by: java.lang.ClassNotFoundException: org.apache.catalina.LifecycleListener
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: EmbeddedMain. Program will exit.

MANIFEST.MF seems to be okay: WEB-INF/lib/tomcat-embed-core-7.0.22.jar contains the missing class.

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: jan
Build-Jdk: 1.6.0_29
Main-Class: EmbeddedMain
Class-Path: WEB-INF/lib/spring-web-3.0.6.RELEASE.jar WEB-INF/lib/aopal
 liance-1.0.jar WEB-INF/lib/spring-beans-3.0.6.RELEASE.jar WEB-INF/lib
 /spring-core-3.0.6.RELEASE.jar WEB-INF/lib/jwt-3.1.11.jar WEB-INF/lib
 /commons-fileupload-1.2.1.jar WEB-INF/lib/commons-io-1.4.jar WEB-INF/
 lib/next-persistence-0.0.3.jar WEB-INF/lib/hibernate-entitymanager-3.
 6.7.Final.jar WEB-INF/lib/hibernate-core-3.6.7.Final.jar WEB-INF/lib/
 antlr-2.7.6.jar WEB-INF/lib/dom4j-1.6.1.jar WEB-INF/lib/hibernate-com
 mons-annotations-3.2.0.Final.jar WEB-INF/lib/jta-1.1.jar WEB-INF/lib/
 cglib-2.2.jar WEB-INF/lib/javassist-3.12.0.GA.jar WEB-INF/lib/hiberna
 te-jpa-2.0-api-1.0.1.Final.jar WEB-INF/lib/kryo-1.04.jar WEB-INF/lib/
 asm-3.2.jar WEB-INF/lib/reflectasm-1.01.jar WEB-INF/lib/minlog-1.2.ja
 r WEB-INF/lib/annotations-1.3.9.jar WEB-INF/lib/tomcat-embed-core-7.0
 .22.jar WEB-INF/lib/tomcat-embed-jasper-7.0.22.jar WEB-INF/lib/tomcat
 -embed-logging-juli-7.0.22.jar WEB-INF/lib/derby-10.8.1.2.jar WEB-INF
 /lib/spring-context-3.0.6.RELEASE.jar WEB-INF/lib/spring-aop-3.0.6.RE
 LEASE.jar WEB-INF/lib/spring-expression-3.0.6.RELEASE.jar WEB-INF/lib
 /spring-asm-3.0.6.RELEASE.jar WEB-INF/lib/spring-orm-3.0.6.RELEASE.ja
 r WEB-INF/lib/spring-jdbc-3.0.6.RELEASE.jar WEB-INF/lib/spring-tx-3.0
 .6.RELEASE.jar WEB-INF/lib/commons-lang-2.5.jar WEB-INF/lib/slf4j-api
 -1.6.3.jar WEB-INF/lib/slf4j-log4j12-1.6.3.jar WEB-INF/lib/log4j-1.2.
 14.jar WEB-INF/lib/jcl-over-slf4j-1.6.3.jar WEB-INF/lib/commons-loggi
 ng-1.1.jar WEB-INF/lib/commons-collections-3.2.jar

Upvotes: 2

Views: 4719

Answers (1)

Jan Goyvaerts
Jan Goyvaerts

Reputation: 3023

I've tried various libraries but I could make none work fully to what I want to do. You've got those that do clever classloading tricks to keep the war file as is. And you've got those which explode all jars into separate files and cram it all into an executable jar.

Of the first category I found that Winstone was the best I could find. Just add the plugin, rebuild and run. And indeed, something deploys the war into an embedded web container. Which is unfortunately not powerful enough to run a complex web application.

I'm ruling out solutions of the second category because of the file conflicts when decompressing jars containing files at the same path. Typically META-INF/.... And more precisely the Spring related meta data. Which has to be merged together into a single file. Otherwise the application simply doesn't start.

I've opted for a third kind of solution: Have the executable jar contain the war file as such. When it is run, it will extract the war file into a temporary directory and run the embedded web container (in my case Tomcat) using the just extracted war file. Additionally opening a browser on the right url.

It's easy to implement and anybody can start it. Although I would have preferred to keep the jar file as such, this avoids any complications due to class loading or exploded jar file clashes.

Upvotes: 2

Related Questions