2

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
Jan Goyvaerts
  • 2,913
  • 4
  • 35
  • 48
  • I think generally, if you want to provide an embedded web server/web service then jetty is the easiest way (http://jetty.codehaus.org/jetty/) – trojanfoe Oct 26 '11 at 14:10
  • I agree. But one of the libraries does not cope with Jetty 7 and 8. That's why I tried with Tomcat embedded. Which worked directly. (Didn't know it existed before today.) – Jan Goyvaerts Oct 26 '11 at 14:15
  • Is it possible jars inside jars are not supported ? – Jan Goyvaerts Oct 26 '11 at 14:46
  • 1
    Yeah I believe you need to unpack your dependency jars and repack all the resulting files into your delivery jar. There are tools to help with this: http://stackoverflow.com/questions/183292/classpath-including-jar-within-a-jar – trojanfoe Oct 26 '11 at 14:48
  • I JUST could make it work : By exploding it with the Assembly plugin, giving it a main class and merging all "spring.handlers" from the various Spring jars into a single "spring.handlers" file. I'll see if one of the two plugins can do that. – Jan Goyvaerts Oct 26 '11 at 15:12
  • The Maven Winstone plugin does it all in one go: http://blog.jayway.com/2008/11/28/executable-war-with-winstone-maven-plugin/ But it doesn't seem to handle Ajax & al. Argh ! – Jan Goyvaerts Oct 26 '11 at 15:41
  • Here's a quick intro on how to use One-Jar: http://blog.jayway.com/2009/03/22/executable-jar-with-onejar-maven-plugin/. But then the trouble is that the embedded tomcat is expecting files on the file system instead of WEB-INF in a jar file. Any clue ? – Jan Goyvaerts Oct 26 '11 at 16:12
  • What was the problem with one of the libraries that meant you couldn't use jetty 7/8? Have you tried it with Jetty 6; that still seems well supported and widely used. – trojanfoe Oct 26 '11 at 21:36
  • It has its particular way with http sessions and goes wrong somewhere. I've tried with Jetty 6, but I didn't find out how to run it embedded using Maven; which dependencies and which classes to use. I'd be more than happy to use Jetty... – Jan Goyvaerts Oct 27 '11 at 07:53

1 Answers1

2

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.

Jan Goyvaerts
  • 2,913
  • 4
  • 35
  • 48