For all its excellent capabilities, as a software system uPortal can be a difficult beast to work with. In its role as a Portal framework targeting the JSR-168 Portlet Specification (soon to be JSR-286, Portlet 2.0), it's very nature is to combine with and aggregate independent software projects. It is also an integration platform: it commonly requires passwords, URLs, driver classes, and diverse configuration settings to communicate properly with external systems.
These responsibilities add complexity to the portal as a software project. It's challenging to manage the relationships between the uPortal software and it's dependent projects, especially Java Portlet applications, but also non-portlet components that form a deployment unit with the portal like Apache or Tomcat. The portal, moreover, commonly expresses itself in multiple environments: production, test, development, local, etc. These environments usually require different data, configuration, integration settings.
This page describes some coordinated practices designed to tame these complexities. These solutions are not the only solutions, and may not be suitable for everyone. All options have advantages & drawbacks.
Jasig Source Code
The first order of business is obtaining source code – uPortal, community portlets, perhaps others – from Jasig. Jasig projects are free open source software (FOSS) and can be easily downloaded by anyone. In fact there are many ways to get Jasig source code, and several things you can do with it once you have it. Not surprisingly, some approaches will put you in a better position for the future than others.
In choosing your methods, one of the leading considerations is how easy will it be to upgrade to future releases of uPortal and/or Jasig community portlets. The answer varies between institutions and from project to project, but always it gets dramatically harder as you apply more local customizations to Jasig source code. This trend applies no matter which practice(s) for managing Jasig source you adopt. But some local changes are unavoidable, and there are tactics that can help you manage these differences when the time comes to upgrade.
Vendor branching is probably the leading practice in software for addressing this class of problem. In essence, it's a strategy for harnessing & applying the differences between version releases of 3rd-party libraries in
svn merge operations. Vendor branching must be set up from the beginning, before you make any customizations.
The canonical setup process is as follows (Subversion):
- Create a space in SVN for vendor project foo at
- Import foo source code under
svn copytag the foo source using the current version name, i.e.
- Again using
svn copy, fold the foo source into your project, i.e.
Now you can make local changes to foo source code where necessary.
Later, you merge changes to foo from future releases using the following process:
/vendor/foo/current/and apply changes from the new release of foo;
- Create a new tag for the foo source based on the new version name, i.e.
- Inside a checkout of
svn mergethe differences to foo between the first tag and the second
- Resolve conflicts (if any);
The vendor branch allows you to apply the difference between foo 1.0.0-GA and 1.1.0-GA using
svn merge. The advantage of
svn merge is it's ability to reconcile these differences with local customizations automatically, provided there are no conflicts. Without the vendor branch, this process must be done by hand. This advantage is the upside of vendor branching; the downsides are in complexity & effort.
Vendor branching makes most sense when:
- You're likely to benefit greatly from the automated merge process (e.g. your customizations extend beyond configuration settings & added files)
- You don't expect to replace the vendor source (vendor drop) very often
- You have a team member who is comfortable with advanced SCM concepts
Subversion Externals Definitions
svn:externals feature is another good alternative for managing updates to Jasig source code. In a nutshell, this feature allows you to federate Subversion repositories: yours, and an external repository hosting 3rd-party source code (Jasig). This approach makes it very easy to change the version – even the revision – of the 3rd-party project that your local version is based off.
A good way to set up
svn:externals is as follows:
- Create an
ext/subdirectory within your project in your subversion, e.g.
svn adda file called
.externalsto this directory; specify the intended value of the
svn:externalsproperty within it
- From inside
svn propset svn:externals -F .externals .to set the
svn:externalsproperty based on the file
svn commit -N . .externalsto commit changes to the file and the
svn:externalsproperty of the
Now if you perform an
svn update from a checkout of
myProject/trunk/ or the
ext/ directory within it, you will also get a copy of the 3rd-party source code pegged on the revision you specified.
Later, you can pick a different revision using the following process:
- Edit the
- From inside
svn propset svn:externals -F .externals .
svn commit -N . .externalsto commit the change
ext/directory within it
This practice allows you to upgrade 3rd-party source code very quickly. In open source, this advantage is a major benefit since it makes it very easy to contribute bug fixes and uncontroversial enhancements to the project directly, then pull them into your project with a revision bump. This process supports a very tight feedback loop between the open source project and the organizations using it. The result is increased activity and a faster rate of progress on the project.
On the downside, this approach does not provide the automated merge capabilities that vendor branching does. In fact it does no merging at all; you have to bring additional tools & practices to bear for merging local customizations with 3rd-party source code. (See Project Overlays below.) Lastly, although putting your bug fixes & enhancements into the parent project first is elegant and greatly streamlined by this practice, it requires access to a project committer.
svn:externals makes most sense when:
- You expect to make few changes to 3rd-party source beyond configuration settings & added files
- You want the freedom to pick up bug fixes & enhancements rapidly as they happen in the community
- You are able to work with a project committer
You can use an overlay approach when you want to work with a pristine (unmodified) copy of 3rd-party source code, but you nevertheless need to apply some local differences such as configuration settings, additional files, skinning, etc. There's more than one way to do overlays, but remember that some overlay approach will likely be needed when you choose the
svn:externals strategy described above.
The Maven WAR Plugin provides baked-in overlay support for WAR projects. It's powerful, and relatively simple to implement. This approach allows you to manage only the file(s) you want to change, pulling in the bulk of project files directly from 3rd-party source.
These are the basic steps for creating a Maven overlay project:
- Create a
pom.xmlfile based on the project you'll be overlaying (you need to build the same way)
- Add the origin project as a dependency (must be
- Add to your project any file(s) in the origin project you wish to replace (must be same name & location)
- Add any additional file(s) your project needs beyond what the origin project has
mvn package(as normal) to build your project (the origin artifact must be in a visible repo)
You will see that, although your
src/ files remain as sparse as you made them, your artifact and your
target/ directory include the entire origin artifact, exactly as if those files were in your project directly. This is the default behavior for Maven overlays; many configuration options are available for fine-tuning this behavior to suit your needs.
This overlay solution is good when:
- Your project & the origin project specify the
- You don't expect
pom.xmlfile of the origin project to change much (you have to keep yours mostly in sync)
"Brute Force" Overlays
Groovy "Puppet Master" Build Script
This section is unfinished. There needs to be some explanation to go with the sample script, and the script itself is missing part of the example (portlets). But if you're familiar with uPortal and Groovy, you may be able to put together the purpose and function of this script just by looking at it.