Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Tomcat only supports the basic Servlet functions while JBoss supports the entire suite of J2EE standard services. When an application decides to use a standard API that is part of J2EE but is not installed in Tomcat, they have to include their own copy of the support library. For example, CAS has JPA support for the Ticket Cache. JPA is built into JBoss and every other J2EE server, but to get that service in Tomcat you have to include a copy of Hibernate (or another JPA implementation) in your WAR.

This creates a potential conflict when CAS comes with a Maven project that includes into the WAR duplicate copies (sometimes at slightly different version levels) of services that JBoss supplies out of the box. Do you continue to use the CAS copy of the service, do you shift over to use the JBoss built in version, and if you do nothing then does the code work at all.

The most complex problem deals with the generic problem of "logging", because there are so many different interfaces, implementations, and libraries all concurrently in use in most applications.

Logging is pretty much the same no matter which library or implementation you choose. There are some slight differences that give way to what seems like a dozen different competing solutions to the same problem (log4j, slf4j, Commons logging, JBoss logging, ...). Among the various optional modules of CAS, and then among all the JAR file libraries that CAS includes, there is some code that uses each available interface. Since this is typical, the libraries are designed to all coexist with each other and they can nicely interoperate. It a standalone application, or in Tomcat, they automatically discover each other and work out their differences. However, when you run a bunch of applications inside a server like JBoss, there are two different ways you might like to operate.

In some cases you want JBoss to control all the logs for all the applications so you have a single unified logging system.

Alternately, the developer of each application may want a separate log for that application that the developer controls independently of JBoss and the other applications.

On paper it should be possible to configure either solution, but in practice we have not figured out how to get JBoss logging to do everything we want for CAS. So at Yale CAS runs under JBoss completely separated from the JBoss logging services and the JBoss provided logging libraries. This is accomplished by adding a JBoss specific configuration file, WEB-INF/jobss-deployment-structure.xml. This file, among other things, lists libraries that JBoss would normally make available to an application that runs under it but where CAS wants to use its own version of the library (or to have no version of library at all). Generally speaking, the Yale CAS version of this file excludes all the expected and obscure logging related libraries for all the logging APIs.

To get the exact opposite result, that is to replace some library that CAS normally includes in WEB-INF/lib with a version of the same code that JBoss supplies as a built in service, the Maven configuration is changed to indicate that the library is "provided" by the server environment.

Maven Dependency Management is supposed to provide the ability to force a specific release of a dependent library across the entire build process. However, building CAS is complicated because it involves compiling the Core library, and then the optional libraries, and then separately assembling them in the Webapp project.Then on top of that, the Yale customizations are added to the vanilla WAR using the CAS recommended technique of Maven "WAR Overlay".

When the dust settles, you occasionally have JBoss complains when CAS attempts to include in WEB-INF/lib:

  • Libraries that should not be explicitly included because they are now part of Java (XML libraries like xalan and xerces).
  • Libraries that duplicate function that is built into JBoss and any other full J2EE server (hibernate, JAXB).

So any library that causes trouble is excluded during the Yale Maven project that builds the final WAR. In addition, the JASIG code add a persistence.xml file in WEB-INF/classes that causes trouble for JBoss, so it is removed.

JBoss provides a number of optional libraries that are not part of the J2EE standard but are commonly used by applications. The biggest problem is JAR files associated with any of the dozen or so "logging" frameworks (log4j, slf4j, commons logging) which all come in JBoss along with its own JBoss logging. JBoss by default tends to replace your logging jar file with its own, but that doesn't generally work. The only way to reliably get all the logs you want is to include a WEB-INF/jboss-deployment-structure.xml with exclude statements for all the log related JAR files. Then logging for CAS is controlled by the CAS log4j.xml file and not the JBoss logging configuration.

Maven Dependency MisManagement

After all the processing, we occasionally find two different versions of the same library included in WEB-INF/lib (example: commons.io Version 2.0 and 2.4). Probably one version was added by the vanilla CAS build process, and then a second version number was unintentionally added during the Yale customizations. You might spend a week of trial and error trying to figure out what you don't understand about Maven Dependency Management syntax, but there is a brute force solution to delete the libraries you don't want (and while you are at it the libraries that conflict with the JBoss enviroment) by specifying the undesirable JAR files in the "packagingExcludes" tag of the maven-war-plugin configuration in the Yale Webapp POM. Basically, this is a place to put in a last minute override and delete of files that you do not want copied to the final WAR artifact.

...