Versions Compared

Key

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

...

Apereo distributes a project called cas-server-webapp to create an initial template WAR file. This WAR is not particularly useful, but it contains at least a starter version of all the Spring XML used to configure CAS and many CSS, JSP, and HTML pages. It also contains a WEB-INF/lib with the basic JAR libraries needed by a CAS system. This unmodified Apereo WAR file is a "template" that Yale modifies or updates to create our final WAR.

Although you can modify the cas-server-webapp project directly, this results in a directory with a mixture of Apereo files and Yale files, and the next time you get a new CAS release from Apereo you have to sift through them to find out which ones have been changed by Apereo.

...

Maven realizes this is a WAR Overlay project because the cas-server-webapp WAR is referenced as a dependency. Since one WAR cannot be included inside another, this is a Maven idiom that everything in this project modifies or adds to this original template warfiles to the cas-server-webapp template WAR file. Files in the Yale Overlay project replace files with the same name in the Template cas-server-webapp project. Files with new names are added to the output WAR. Unfortunately, there is no elegant way to delete All the XML, CSS, HTML, JSP, and other files in the Template project that you no longer want. There is, however, an Exclude list of files that can be configured in the plugins section of the Overlay project POM that deletes files inelegantly. Yale uses this to delete libraries that Apereo adds to their WAR so it can run in Tomcat, but which we do not want when it runs in JBoss or under Java 1.7 (because newer versions of the same API are built into our execution environment).

Version Numbers and Project Structure

The first Apereo version of CAS was 3.0.0 and now there are CAS 4.x versions. CAS 1 and CAS 2 were written at Yale and are no longer meaningful, but this means that the Maven version numbers starting 1.x and 2.x are free and will never be used by Apereo. So Yale internally is reusing the Version values of 1.0.x, 1.1.x (for our work with CAS 3.5.2) and 1.2.x (for our work with CAS 4).

This means that the actual CAS module that will go into production is stored in the Yale Artifactory network server as https://repository.its.yale.edu/maven2/libs-releases-local/edu/yale/its/cas/cas-server-war/1.1.1/cas-server-war-1.1.1.war, but it will be build using a vanilla Apereo JAR file stored as http://repository.its.yale.edu/maven2/simple/libs-releases-local/org/jasig/cas/cas-server-core/3.5.2/cas-server-core-3.5.2.jar. It is important to always distinguish the pairs of Version numbers for the Yale components and Yale modified code and the corresponding vanilla Apereo release.

Although there may be additional code in various stages of development, a CAS release at Yale only depends on three Yale projects:

  • cas-server-expired-password-change (to prompt the user to change a password that is a year old)
  • cas-server-support-CushyTicketRegistry (only the configuration module is currently used to configure ehcache)
  • cas-server-yale-webapp (the WAR Overlay with all the Yale configuration and HTML changes)

You could create an Eclipse workspace that included only these three projects. The cas-server-yale-webapp project could be configured with <dependency> statements for the corresponding Apereo release (3.5.2 or 4.0.0) and, of course, it would depend on the JAR files built by the other two projects. That would build a version of CAS that deployed and ran at Yale.

However, if you have any problems that you need to debug, or you find a problem in Apereo code and cannot wait for them to fix it, then you need a way to organize a mixture of unmodified and modified Apereo JAR files.

Yale does not want to modify Apereo code. Even when we find a bug and fix it, if the bug is not critical we may prefer to use the unmodified Apereo module with the bug over deploying a Yale modified version of the same JAR file. However, this is not always possible. It is unreasonable to decide late in a release to switch to a modified version of an Apereo JAR, so Yale adopts a convention.

  • Whenever we start to work with a new version of Apereo CAS, we configure the projects so that Yale can easily modify any code and deploy the modifications cleanly and without confusion.
  • We almost never actually use this capability.In some releases we don't use it at all.

The rest of this section is to explain how we organize the capability we almost never use. If you need it, you will appreciate why all this effort was worth it.

The trick is manage the version numbers assigned to each project. Remember that, for example, Yale Version 1.2.0 corresponds to Apereo Version 4.0.0.

If you download or check out the Apereo 4.0.0 release and look through the POM files, you will note that:

The top level (parent directory) POM has

Code Block
  <groupId>org.jasig.cas</groupId>
  <artifactId>cas-server</artifactId>
  <packaging>pom</packaging>
  <version>4.0.0</version>

While all the subdirectories reference this directly astemplate WAR that do not appear in the Yale WAR Overlay project are simply copied to the output WAR as is.

While the WAR Overlay process provides a way to update, replace, or add files, it does not provide any way to delete files you no longer want. However, the Maven WAR building plugin can be configured in the WAR Overlay POM with an "exclude" list of files to remove from the template WAR. There are two cases where this is used:

  • Apereo builds CAS for Tomcat, which provides only a limited number of libraries to the applications, and so it will run on older versions of Java. Yale runs CAS under JBoss which provides a larger number of libraries standard, and JBoss expects later versions of Java. JBoss complains at startup when it finds that a WAR file contains JARs in its WEB-INF/lib that conflict with libraries built into JBoss. We exclude the libraries that JBoss or modern Java provide by default.
  • Sometimes Apereo code depends on a slightly older version of a JAR file, but Yale code requires a slightly newer version of the JAR. If cas-server-webapp had a dependency on 1.2.3 and Yale depends on 1.2.4, then the normal WAR Overlay process would copy both versions of the JAR file (1.2.3 and also 1.2.4) to the output WEB-INF/lib. So we add an Exclude statement to delete the old version (1.2.3) to make sure the version we want is the one we get.

Version Numbers and Project Structure

The first Apereo version of CAS was 3.0.0 and now there are CAS 4.0.x versions. CAS 1 and CAS 2 were written at Yale and are no longer meaningful, but this means that the Maven version numbers starting 1.x and 2.x are free and will never be used by Apereo. So Yale internally is reusing the 1.x Version numbers for Yale modules and for Yale modified versions of Apereo modules. Since Yale only periodically updates its CAS version, we skip over a lot of Apereo version numbers:

Apero VersionYale Version
3.4.x1.0.x
3.5.x1.1.x
4.0.x1.2.x

 

This becomes important (and confusing) when Yale has to make a change to an Apereo JAR file to fix a problem we cannot ignore and cannot wait for a new Apereo release. In the Maven repositories there will be a vanilla Apereo artifact ending in *-4.0.2.jar and Yale will then add its own artifact named *-1.2.0.jar. If the artifact is one of the optional libraries, then we will simply add the 1.2.0 dependency to the WAR Overlay project, but if this is cas-server-core or anything else in the template WAR built by the cas-server-webapp project then we also have to add the -4.0.2.jar file to the Exclude list of the Maven WAR plugin configuration in the WAR Overlay POM file.

Although there may be additional code in various stages of development, a CAS release at Yale only depends on three Yale projects:

  • cas-server-expired-password-change (to prompt the user to change a password that is a year old)
  • cas-server-support-CushyTicketRegistry (only the configuration module is currently used to configure ehcache)
  • cas-server-yale-webapp (the WAR Overlay with all the Yale configuration and HTML changes)

In CAS 3 development Yale created a source project that included the standard Apereo source along with the three additional Yale projects in a single directory. The advantage of this project structure is that Yale was recompiling all the source and was building at least formal artifacts with the Yale version numbers for all the Apereo code. If Yale ever wanted to change an Apereo module, all it had to do was to make a change in the Apereo source and then change the dependency version number for that artifact in the WAR Overlay from the vanilla 3.5.x to the Yale 1.1.x. It made modifications to Apereo easy, but it created a lot of work when you upgraded to a new CAS release where you ended up changing the project structure of a bunch of Apereo modules you were never really going to change.

So in CAS 4 we change the Yale project structure to a much simpler and cleaner approach. All the vanilla Apereo code is removed initially. If there are modification we need to make to an Apereo module, that will be a bunch of work we can do later on when it is needed. The Yale project then consists of only the three Yale added projects as subdirectories of a parent CAS project, plus a parent POM as the only file in that parent directory.

The Yale parent POM is a modified version of the parent POM in the vanilla Apereo CAS 4.0.2 source directory. First, we change the version number from 4.0.2 to Yale's 1.2.0 because that is the default version of any Yale written or modified code. Then we comment out all the processing that Apereo has added to Maven to do open source project housekeeping. When you build an open source project for general distribution, there are Maven plugins that make sure that your comment files list the open source licenses of all the open source dependency libraries you use, and plugins that complain about syle (missing JavaDoc commments for example), and plugins that do special release packaging. Yale is a customer and our projects only have to run at Yale, so we don't need all those checks.

We should note that there are two distinct meanings to the term "parent" in a Parent POM.

The parent directory is a Maven project with a POM file with a packaging type of "pom".  For example, the Apereo parent POM for CAS 4.0.0 begins with the following declaration:

Code Block
  <groupId>org.jasig.cas</groupId>
  <artifactId>cas-server</artifactId>
  <packaging>pom</packaging>
  <version>4.0.0</version>

This file is processed when anyone does a Maven "mvn install" operation on the parent directory. In this case, the important part of the Parent Directory POM is that it contains "<module>cas-server-core</module>" statements for every subdirectory that builds an artifact. Maven processes each <module> statement in the order they appear in the Parent Directory POM file, so this file can be written so that a JAR file is built and stored in the Maven repository before a subsequent module is compiled that depends on that JAR file.

There is, however, a second meaning of "parent" that relates to the projects in the subdirectories. Each subproject POM file contains a <parent> reference:

Code Block
  <parent>
    <artifactId>cas-server</artifactId>
    <groupId>org.jasig.cas</groupId>
    <version>4.0.0</version>
  </parent>

The subprojects inherit the <version> value of the parent they reference. Most of the time, Yale projects are going to want to use and depend on Apereo vanilla JAR files, so inside each Yale project there should by default be a dependency on a 4.0.0 version of all dependencies.

However, the only reason for having Apereo source in the first place is that you may eventually have to change it. When you do, it is no longer Version 4.0.0, nor will it logically have any other Apereo Version number like 4.0.1. Modified code becomes Yale code, and to make that clear it has to have a Yale Version number. So even though you have not changed a single line, the first thing to do with the project is to assign everything the Yale version number it would have if at some future point we needed to change it and deploy the changes. That means changing the 4.0.0 in the parent project and all the subprojects to whatever is the current Yale version number (1.2.0-SNAPSHOT in this example).

Of course, the additional Yale projects also have the same Version number. They have to go into the final cas.war artifact that gets deployed and run on the CAS servers. However, if you now build the Apereo parent project and all its subprojects, you will now get a 1.2.0-SNAPSHOT version of cas-server-core and all the other code. Not only will these JAR files not go into Yale production CAS, they may never be used at all, not even in Sandbox testing. There is no need to include any of the generated 1.2.0-SNAPSHOT JAR files in anything you are doing. The reason for the version number change, and the resulting JAR file name change, is to guarantee a clear distinction between anything you build and the pure vanilla unmodified Apereo version of the same code.

If the WAR Overlay project builds a cas.war file that contains WEB-INF/lib./cas-server-core-4.0.0.jar, then you know it is using vanilla Apereo code. If instead it contains WEB-INF/lib./cas-server-core-1.2.0.jar, then you know it is using a JAR file you compiled. Whether there are any changes to the original source and what those changes are you can only determine by checking the Subversion history, but the JAR file name makes it clear that this library has some Yale modifications.

If the very first thing you do is to change the Version values for all the source projects, then you are assured that Yale modified versions of Apereo modules cannot accidentally get installed. The normal Build process compiles libraries and replaces them in the Artifactory network server. Once a Yale modified version gets installed on top of an Apereo file with the same name, it will be very hard to straighten things out. If the Yale compiled versions always have a different version number and file name, then you know that putting an Apereo Version number in a <dependency> statement will always end up including unmodified Apereo code.

With this preparation, it is no longer necessary or even useful to separate out the Apereo source code from the Yale source code. The Yale projects can be added as new subdirectories of the Apereo parent project, and new <module> statements can be added to build them. The combined Apereo and Yale code can be checked into Subversion, and it can be built with the Jenkins Trunk Build project.

However, when Jenkins builds cas-server-core or cas-server-webapp this way, it creates a version 1.2.0-SNAPSHOT of the artifact. Just because that version is created during the Build job does not mean that it actually ends up in the cas.war. The version that finally goes into the deployed artifact is the version referenced explicitly by number in the cas-server-yale-webapp project, and most of the time that will be 4.0.0.

Why Not Vanilla?

During development, we may make changes to vanilla CAS source to see how something works or to track down a problem. Those changes will be abandoned in the final deployment. The only time we deploy a Yale modified version of a standard Apereo JAR file is if there is a critical Yale bug fix that we need for reliability, or if we have a serious difference of opinion with the Apereo source committers.

.0.0</version>
  </parent>

The <parent> directory contains DepedencyManagement statements, Maven plugin configuration statements, and <parameter> definitions that are shared by all the subprojects that reference it. This ensures that, for example, all the subdirectory projects are complied with the same version of the Apache commons-io JAR library.

It is a common Maven programming convention that the <parent> POM is also the Parent Directory POM. That is the way that Apereo organizes CAS and it is the way that Yale organizes its CAS additions project, but it is not a requirement. Technically, the Parent simply has to be a project of type "<packaging>pom</packaging>" that has already been processed by Maven and has already been stored in the Maven local repository before it is referenced in a <parent> statement of a subproject POM. When the <parent> POM is also the Parent Directory POM and Maven is invoked to build the parent directory, then by definition the Parent Directory POM is processed first and is stored in the Maven Repository before any of the subdirectory projects are built. However, Shibboleth 3 is an example of another approach where the <parent> POM is itself a subdirectory and the Parent Directory POM but is the first <module> statement and is therefore built and stored in the local Maven repository before any of the subprojects that reference it.

The vanilla Apereo CAS source project has its Parent Directory POM that establishes the global defaults and builds all the Apereo artifacts at version 4.0.2. You can recompile them in your sandbox or you can simply let Maven download the artifacts from the Yale Artifactory network server or from the Internet. Then the Yale CAS source project has its modified version of the Apereo Parent Directory POM with all the open source project boilerplate processing commented out and maybe a few version numbers incremented (for example, Yale changes the Java compiler versions from 1.6 to 1.7 for its own coding). The WAR Overlay (cas-server-yale-webapp) project can get the template WAR from an instance previously complied on the sandbox machine and stored in the local Maven repository, or it can get the standard version of the template WAR complied by Apereo and stored on the internet servers. Either way the template WAR is the same file (except for timestamps) and the WAR Overlay processing produces the same result.

In CAS 3.5.x (Yale version 1.1.x) the Yale CAS source project contains the three Yale subprojects, but it also contains a bunch of vanilla Apereo source subprojects. Some of them build Yale versions of Apereo modules (that is, a cas-server-core-1.1.1.jar file), but just because we build a Yale version of the artifact doesn't mean that it is ever used or deployed anywhere. If you look at the WAR Overlay project (cas-server-yale-webapp) you may find that the <dependency> statement in that POM references the vanilla Apereo Version number (3.5.2.1) and so the Yale version of the artifact we have just compiled is stored but ignored. If you are debugging a probem and need to add trace statements to the vanilla Apereo code on the Sandbox, you can temporarily change the Version number in the WAR Overlay to use your modified code, but then after the problem has been resolved you can revert the WAR Overlay POM to its standard settings and go back to using vanilla Apereo code.

Because the CAS 4.0.x (Yale version 1.2.x) project does not normally contain a copy of any Apereo project, making temporary changes for sandbox debugging is a much larger amount of work. You have to build a custom version of the Apereo JAR file, and that means making all the necessary changes to the project and subproject directories to make it work. It is important if you do this to NEVER compile a modified version of the Apereo source and store it in the local Maven repository under the vanilla Apereo version number. Once you have stored your own modified version of cas-server-core-4.0.2.jar then without some custom cleanup on your part it will override the real vanilla version of the module and you will always get the modified version on that Sandbox machine. So if you decide to do some work on a previously vanilla Apereo project, the first thing to do is to change the Version number in the project POM.

Why Not Vanilla?

Apereo code contains some bugs or sloppy coding. Yale has found them and reported them informally, but there has not been much interest in fixing them. Some examples of differences of opinion or bugs:

...