For all our projects (http://www.onehippo.org) we're going to standardize by default on Tomcat build, test and deployment integration using Cargo.
As our projects concern in general multi-war setups with shared classloader configuration requirements, I've enhanced the current Cargo trunk for Maven2 and mainly Tomcat to fix and (re?)enabling shared and extra classpath configurations for Tomcat and Maven in general.
Currently the Maven plugin doesn't support shared classpath configurations yet.
Furthermore, extra classpath configurations seems to be "broken": although extra classpath can be configured there is no code (anymore?) which actually does something with it.
Note: there is a unit test for this, ExtraClasspathOnStandaloneConfigurationTest, but that also doesn't actually depend on (thus neither validate) any class on the extra classpath...
I'm providing the following solution:
- Extended Maven2 configuration Dependency class with new property "classpath" through which you can configure if a dependency is for either the "extra" classpath (default) or "shared" classpath.
- Enhanced Container.setupExtraClasspath method to check this classpath property to only add a dependency if it has this classpath property set to "extra" (again: the default)
- Added method Container.setupSharedClasspath similar to the setupExtraClasspath but instead checking for classpath property with value "shared" (not default), and have this method called from Container.createContainer.
- Support "runtime" scoped dependencies also which are not/should not be visible during project compile/build like typically JDBC drivers etc.
For this I changed for the relevant Maven Mojos the annotation @requiresDependencyResolution compile (or runtime) to @requiresDependencyResolution test
Maven doesn't expose both "provided" and "runtime" dependencies as project artifacts to a plugin unless you use "test" resolution, see also: http://maven.apache.org/developers/mojo-api-specification.html
Changing the required dependency resolution allows the plugin to see all dependencies configured, so including "runtime" or even "test" if desired.
- Partly rewrote AbstractCatalinaStandaloneLocalConfiguration.doConfigure: (Tomcat only fixes)
- copy the configured shared classpath entries (as file) to predefined container folder "shared/lib" (see explanation below) as FileConfig property (copying itself done automatically)
- copy the configured extra classpath entries (as file) to predefined container folder "common/lib" (see explanation below) as FileConfig property (copying itself done automatically)
- changed tomcat5x, tomcat6x and tomcat7x catalina.properties:
- removed Ant filter token @catalina.common.loader@ (no longer used)
- added to common.loader: $
- added to shared.loader: $
The current logic to reference the shared classpath dependencies by injecting them on the Tomcat common.loader configuration (using Ant filter token @catalina.common.loader@)
has two major problems:
1) The Tomcat commmon.loader configuration is supposed to be used as classpath "shared" between the container and the applications, but is not the applications shared classloader.
The Tomcat common.loader should be used for dependencies which are typically configured through the Cargo extra classpath configuration (hence the above redefinition).
In Tomcat5x the common.loader this was also used/seen as the endorsed classloader, typically used for things like jdbc drivers, XML parser overrides, etc.
The Tomcat shared.loader configuration defines the classloader which is not shared with the container but only between the (web) applications, so this is the one which should be used for the Cargo shared classpath entries.
Note: there is also yet another Tomcat classloader configurable, server.loader, which can be used to add classes to be seen only by the container itself. AFAIK there is no corresponding Cargo construct/logic for this.
For those unfamiliar about the different Tomcat classloaders, a good explanation can be found here: http://pragmaticjava.blogspot.com/2009/01/tomcat-6-and-class-loading.html
2) As the shared classpath entries were configured as file references only on Tomcat, this worked fine for locally running the container, but breaks when the container was packaged up (e.g. using the cargo:package plugin)
and moved/copied elsewhere. By actually copying the classpath entries by file inside the (local) container deployment instead, a valid "standalone" packaging now is possible.
Note: this issue is created as follow up on
CARGO-920 dealing with only the shared/extra classpath improvements (multi-module support no longer is needed).
I will attach a new, code-only, patch for these changes shortly and a reworked example multiapp project to show its usage.
Thereafter I'll start with the needed documentation updates and provide a patch for those later as well.