package libaries jars in separate jar from main war

I use maven in Eclipse to package my application. I would like to separate the libary jars from the main application war… So basically, when maven thinks it is needed:

  1. Build application war
  2. Build jar with all jar that currently in war so I can put it in the tomcat lib directory

My libraries don’t change that often, and there is a good chance I will have multiple tomcat webapps pointing to the same war file ( via $TOMCAT/conf/Catalina/localhost/.xml ). As such, it would be nice the be able to share these libraries. Saves space and cuts down on download time ( because of reduced size of war file ). I am a maven newbie, so might be missing something obvious. If this is type of maven question that you guys don’t feel comfortable answering, maybe tell me sort of what to ask in those maven communities.

Thanks.

Ok, maybe I am looking at this the wrong way. How do people normally separate out the libraries so that the WAR file is not so big and the common libraries can be shared?

The only way I can think to do this would be multiple steps:

  1. Exclude “jar” files from war in pom.xml, just like we exclude unnecessary GWT stuff, using “” tag
  2. Write some script or maybe maven can do this: report jars changed or added since last build

Is there a better way? Is there a way to do step 2 in maven?

if this is explained in some Vaadin documenation that I just missed, point me in the right direction, with my appologies.

Hi,

I’m not sure if doing so is a good idea, but the

provided

scope may help:



provided

This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes.

Just make sure you don’t end up in a
JAR Hell
:wink:

Thanks, this looks promising. Don’t get me wrong, I see your point about JAR Hell, and definitely thank you for that warning, and will keep it in mind.

BTW, my main issue is that, for my setup, when my war is expanded two times ( for two different webapps ), it has the same exact jars in both places. This especially happens with the VAADIN common code, but it is just as important for all the common jars. For instance, below ( near the bottom of the post ) are portions of two different tomcat deployment files. Note that they have the same docBase, but differ in the socketType ( which point to different backend/server processes, accessing different DBs ) and maybe one or two other parameters. They produce, as just one example, the following jar duplication. I know they are duplicates because they both come from the exact same “war” file, thus the same file time stamps.

-rw-r--r--. 1 tomcat tomcat 2840580 Jul 7 21:45 /usr/local/tomcat/webapps/turnsmith/WEB-INF/lib/jaxb-0.3.6.jar -rw-r--r--. 1 tomcat tomcat 2840580 Jul 7 21:45 /usr/local/tomcat/webapps/vaadinwebsite/WEB-INF/lib/jaxb-0.3.6.jar I am just trying to avoid the wasted space of such duplications. If I am going about this the wrong way, tell me. Seemed like the best way to me, and how I have done it with other websites pre-Vaadin and pre-Maven.

::::::::::::::
/usr/local/tomcat/conf/Catalina/localhost/vaadinwebsite.xml
::::::::::::::

<Context docBase  = "[b]
${catalina.home}/wmsvision/vaadinwebsite.war
[/b]"
    override      = "true"
    swallowOutput = "true"
    debug         = "0">

  <Parameter name = "socketType"
      override    = "false"
      value       = "WMSWebsite" />
      <!-- value       = "Turnsmith" /> -->
      <!-- value       = "WMSWebsite-NEWCUST2" /> -->
....
</Context>

::::::::::::::
/usr/local/tomcat/conf/Catalina/localhost/turnsmith.xml
::::::::::::::

<Context docBase  = "[b]
${catalina.home}/wmsvision/vaadinwebsite.war
[/b]"
    override      = "true"
    swallowOutput = "true"
    debug         = "0">

  <Parameter name = "socketType"
      override    = "false"
      value       = "Turnsmith" />
      <!-- value       = "WMSWebsite" /> -->
      <!-- value       = "WMSWebsite-NEWCUST2" /> -->
...
  <Parameter name="wmsReports" override="false" value="/usr/local/tomcat/wmsvision/wmsReports" />
...
</Context>

Ok, I admit, I have not tried “provided” yet - was not a huge issue before, and I could stomach it ( for a time ). But now my war file jumped from 43 MB to 83 MB ( because I added some jasper and JDBC libraries ). So is there any new advice on this topic before I dig into “provided” or adding “WEB-INF/lib/*.jar” to my POM file?

I expect if I limit my tomcat instance to only my vaadin applications that all use the same exact library jars, it should be pretty safe and stay away from the referenced “JAR Hell”, just double checking there are not better options. I have learned a lot in the past 6 months ( since I started this thread ), but I am still no Maven or Vaadin expert.

Hi,

I believe “provided” is something you should use especially for things for JDBC libraries, that’s pretty much the classic use case for not including something in a project itself.

Best regards,
Olli

“provided” caused other problems in testing, so I chose using the maven “WEB-INF/lib/*.jar” configuration.

So is there a way to instead ZIP this lib folder in “maven”? Basically, in my ideal world, I would love to see two files in the “target” directory:

  1. target/vaadinwebsite-1.0-SNAPSHOT.war - the “war” file is the normal application war
  2. target/vaadinwebsite-lib-1.0-SNAPSHOT.zip - the “zip” file is simply a zipped archive of “target/vaadinwebsite-1.0-SNAPSHOT/WEB-INF/lib” ( for ease of downloading to the production server ).

I have been Googling this question some and so far I have not found a way to do it automatically. I guess I could be phrasing my searches wrong, so even some advice on a better way to ask this question would help.

Hi,
to produce the zip with the dependencies you can use maven assembly plugin.
With
mvn assembly:single
the following configuration will produce a zip file named xxx-all-deps.zip in target
You can also bind the goal to the package phase

In pom file

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>3.0.0</version>
  <configuration>
    <descriptors>
      <descriptor>src/assembly/deps.xml</descriptor>
    </descriptors>
  </configuration>
  <!--
  <executions>
    <execution>
    <id>make-assembly</id>
    <phase>package</phase>
    <goals>
      <goal>single</goal>
    </goals>
    </execution>
  </executions>
  -->
</plugin>

The descriptor in src/assembly/deps.xml

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
  <!-- TODO: a jarjar format would be better -->
  <id>all-deps</id>
  <formats>
    <format>zip</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>false</useProjectArtifact>
    </dependencySet>
  </dependencySets>
</assembly>

HTH
Marco

why do you say “TODO: jarjar format would be better”? Also, how is it only getting the dependencies for my project?

Also, related to my original question and goal, has anyone ever noticed one Design.read failing because it cannot find a custom component class for a given application when we move libraries to shared/lib, but working just fine if we keep the jar inside the war? So some calls to “Design.read” work fine, just one does not. I know for a fact the class is there - I see it in the war file with no libary jars, and it suddenly works just fine when I add the library jars back to the war file.

Just a hunch, but sounds like it could be a classloading issue. Tomcat most likely loads your shared libs with a different loader than the webapp libs. See e.g. https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html

What’s your exact setup here? Vaadin JAR’s in shared, custom component and application in webapp?

Hi,
forgive the TODO comment; it is a copy-paste from maven assembly plugin documentation.
When you define a dependency set in assemblly descriptor by default all dependencies scoped as runtime are taken;
you can then filter them out with other configurations (includes, excludes, useTransitiveDependencies, scope, …).

Regarding your problems with Design.read I agree with Risto; they may be caused by classloading issues.
For the same reason I would not suggest you such a deployment solution; I prefer a fat war with all libraries isolated in webapp classloader.

Best regards
Marco

To answer your question: Basically, I was going to put all library jars into the shared lib ( jasperreports, vaadin, mysql connector, etc, basically everything in my project’s WEB-INF/lib folder ), and then the war has the real application stuff, all the stuff I personally wrote, including this component that Design.read was having a problem finding.

That said, it occured to me last night that maybe I am going about this all wrong. Marco is confirming this theory. I could, in theory, set “unpackWARs=‘false’” in my Tomcat server.xml file, then set unpackWAR=true for web apps where I really need the war unpacked. I am researching this now.