CAS development at JASIG is currently hosted in Git. Yale production deployment standards are currently based on Subversion. Fortunately, Yale has been able to meet its requirements while using the standard distributed JAR file artifacts from JASIG, so there is no need to do local management of the JASIG source. During development it is useful to read source and sometimes debug into a JASIG module, so the first step is to obtain a full vanilla source copy of the release you will be installing as your base. You can check it out with Git or obtain a zip file from JASIG. This source may be checked into Yale SVN, but that is simply for convenience.
The preferred mechanism for local configuration is called the "WAR Overylay" method. This is an option of the Maven plugin that manages projects where the POM indicates "war" as the type of packaging (the type of artifact produced by the project). WAR Overlay processing is triggered when a "war" project has a dependency that is itself also a "war". With an overlay, the plugin reads the dependency WAR file in, replaces or adds files from the current project, and then writes the resulting merged/updated WAR file out to the repository.
Source Build
The standard JASIG CAS project has a parent "cas-server" directory with a POM of type "pom". This project doesn't create anything itself. It contains the common parameters and dependency management for the subprojects that are distributed as subdirectories of the parent directory. A list of Modules in this parent POM indicate the subprojects that Maven should build:
- cas-server-core - This is the single really big project that contains most of CAS Server code and build the big JAR library artifact. It is built first and all the other projects depend on it and the classes in the JAR file.
- cas-server-webapp - This is a dummy WAR file that contains the vanilla version of the JSP, CSS, HTML, and the XML files that configure Spring and everything else. The dependencies in this project load the basic required JAR libraries into WEB-INF/lib. This WAR is not intended to install or run on its own. It is the input to the second step WAR overlay where additional library jar files will be added and some of these initial files will be replaced with Yale customizations.
- Additional optional extension subprojects of CAS supporting specific features. For example, the cas-server-support-ldap module is needed if you are going to authenticate netid passwords to AD using LDAP protocol (you can authenticate to AD using Kerberos, in which case you don't need this module). A JASIG standard distribution includes all possible subprojects and the parent cas-server POM file builds all of them. To save development time, you can comment out the subproject <module> statement in the parent POM of modules you don't use. Disk space is cheap, and deleting the subdirectory of modules you don't use may be confusing.
- Yale CAS extension JAR projects. For example, the cas-server-expired-password-change module is the Yale version of what CAS subsequently added as a feature called "LPPE". Yale continues to use its code because the Yale Netid system involves databases and services beyond simply the Active Directory component and support
- cas-server-uber-webapp - This is the "sample" version of the local customization WAR Overlay project. Yale customization is (unless it is impossible) stored in this directory. If we need Java code, we put this source here and it is compiled and ends up in WEB-INF/classes. We replace some standard JSP and CSS files to get the Yale look and feel and wording. The XML files that configure Spring and therefore CAS behavior are here. This project must always be the last module executed. The cas-server-webapp project is a dependency, so it is the base WAR file that will be updated. This project replaces JSP, CSS, and XML files in the base WAR with identically named files from this project. It adds new files and library jars (from the dependency list of this project). Details will be described below, but this is where all the action happens.
Sanity requires that all of the components of the final CAS Server be compiled and tested with the same version of any library JAR file on which it depends. Unfortunately, there is no automatic way to get this right. Typically, version numbers will be specified in the POM file of the parent cas-server project and as long as that is inherited by all the JASIG projects and all the Yale custom projects, then everything will be in sync and the right library will be in the WAR file. There are two sources of potential problems: JBoss may require (or strongly recommend) that you use a later version of some library than the version JASIG was configured to use, or Yale customizations may require a newer version. The only sensible solution is to change the POM file in the parent cas-server project and then recompile everything to use it. Under no circumstances should the WAR Overlay project introduce a different version of a library being used by other component modules. WAR Overlay only replaces identically named files, and it would include both libraries if the base compoenents depend on quartz-1.6.1.jar and the WAR Overlay project introduced a second dependency on quartz-1.6.2.jar.
This produces some tension in the preferred directory structure during development. It is a convention to put subprojects as subdirectories of the parent project. This structure mixes Yale custom JAR file project subdirectories and the Yale version of the WAR Overlay project subdirectory into the directory tree of the standard JASIG CAS distribution. It reflects the logical structure of the build process (sanity) but then mixes JASIG and Yale subdirectories (not best practice).
Although it is the common practice, Maven does not require the parent POM to be in the parent directory. So you can have a mostly vanilla JASIG source directory and a separate directory with just the Yale JAR projects and the WAR Overlay project. This separates the building of the JASIG standard source from the building of the Yale code, but that creates two separate source build jobs and requires you to remember to rebuild the standard JASIG components any time a dependency version number changes. So you can shoot yourself in the foot here, and you need two different Jenkins production source build jobs for the separate directories.
Look at subversion to see which of the two approaches has most recently been checked in. If you strongly prefer the other, feel free to use it for the next release. Do not feel bad if the person who next installs CAS changes it back.
The POM in a vanilla JASIG component subproject will have a Version number that corresponds to CAS releases (3.5.2). The POM in a Yale customization subcomponent will have a Version number that corresponds to the Yale CAS installation "Release" number for Jenkins tracking (1.1.0-SNAPSHOT). Since the WAR Overlay project has the Yale version number, and that is the WAR that actually gets copied over to JBoss and installed, that is the version number that will be a parameter to the Jenkins job.
The Installer
CAS has a Yale standard Installer project. By convention, the WAR file is downloaded from Artifactory and is then copied to the JBoss deploy directory by an Ant script running under a separate Maven project.
Standalone.xml
In JBoss 5 the datasource definitions for databases and an XML file configuring JBoss JNDI were generated during the Installer step and copied to the JBoss deploy directory. This is no longer the way to do things for JBoss EAP 6.1. Production services has to make sure that the configuration file for the JBoss instance contains the XML to define datasources and JNDI.
To Work on Current Release
Check out from SVN the current version of the cas-server source. (If the Yale source is in a separate directory check it out too, but it has probably been added as subdirectories of the cas-server directory.) Check out the Installer project directory.
If it is at all possible, make changes only to the WAR Overlay project subdirectory.
Sometimes you need behavior that is just slightly different from an existing JASIG version of some bean. The design of CAS is to have standard interfaces, classes that implement these interfaces, and configuration done with Spring XML files that select the appropriate implementation class using a <bean> element. If the class you want to change is configured this way to Spring (search for its class name in XML files), then you can often make a copy of the JASIG source in the WAR Overlay src/main/java tree, changing the org.jasig package name to edu.yale and so on. Then change the behavior of the source you just copied. Now go to the XML configuration that references the original class by name and change the fully qualified classname to match the new class you just created. Typically the interfaces don't change between releases, so you may not have to update your modified source when you migrate to a new release.
What cannot be changed in the WAR Overlay project? If a class or interface is referenced by import in Java source, then the Java mechanism to search for a class by name (the "ClassLoader") typically searches first for a class of the desired name that came from the same source as the class that is looking for it. JBoss regards the WEB-INF/lib and the WEB-INF/classes as two separate sources. Although WEB-INF/classes is said to be "searched first", when some code in cas-server-core is looking for a class name it will find the version of that name that is also in cas-server-core and will not find something with the same name in WEB-INF/classes. So in general you cannot simply copy any org.jasig source to the WAR Overlay source directory, compile it, and then assume that the version you just compiled will override the original code because it is in the "classes" directory and "classes is searched before lib". Think really hard if you need to change something here, but then if you really need to change it you need to make a modification to the original JASIG source and then copy and reconcile that change to each subsequent release.