Overview
The Apache MyFaces project provides a number of different "artefacts":
- MyFaces Core (JSF specification implementation)
- Tomahawk
- Trinidad
- Orchestra
- etc.
There are cases where these projects have "utility" classes in common. In particular, MyFaces Core and Tomahawk have quite a lot of common code. It would not be good software engineering for each project to maintain its own copy of these classes, as bugfixes and enhancements would need to be applied separately to each. The "shared" code is therefore stored in the source code repository as a separate "module".
When bound to myfaces-impl, myfaces-tomahawk, or myfaces-orchestra the shared classes get another namespace. For example, "org.apache.myfaces.shared" becomes:
- org.apache.myfaces.shared_impl.* when used in the myfaces-core project
- org.apache.myfaces.shared_tomahawk.* when used in the myfaces-tomahawk project
This module can be found in svn at:
- http://svn.apache.org/repos/asf/myfaces/shared/
Design and Use
In versions of MyFaces-Core/Tomahawk up to 1.1.1, the shared code was built as a a separate jarfile that must be present in the classpath in order to use either MyFaces Core or Tomahawk. Unfortunately this had a number of drawbacks, the most serious being that only versions of Core and Tomahawk that use the same version of the shared library could be deployed together. If a user wanted to upgrade to a newer release of Tomahawk to fix a bug, then they had to upgrade to the matching version of the shared lib - which then meant upgrading to the matching version of Core too. It also meant that the MyFaces project effectively had to release Core and Tomahawk at the same time (ie tie their release cycles together).
As more MyFaces projects are created which use the shared code, this problem only gets worse.
To resolve this, releases of MyFaces-Core and Tomahawk 1.1.2 or later pre-process the code in the shared module at compile time; the package "org.apache.myfaces.shared" becomes "org.apache.myfaces.shared_impl" (for Core), "org.apache.myfaces.shared_tomahawk" for Tomahawk, and is similarly renamed for other projects. The resulting classes are then included directly into the project's jarfile, removing the need for an extra "shared" jar. This allows various projects that use the shared code to be mixed without conflicts over shared code versions, and allows different release cycles for each project.
This process of modifying the package-name can be thought of as a "primitive OSGi" if you like; a way of running multiple copies of this library concurrently. However rather than relying on custom classloaders to implement this (as OSGi requires), a simple package hack is being done.
Note that this kind of "package renaming" has been used elsewhere. In particular, the Sun JDK itself repackages a number of libraries; for example org.apache.xerces can be found in the standard rt.jar file as com.sun.org.apache.xerces. In release 1.4 of Java, Sun did not do that, and the result was some very ugly conflicts when users tried to put a more modern version of xerces in the classpath. The shared project is implemented as it is for very similar reasons.
What are the submodules of Shared for?
Ideally, there would be just one "shared" project, and any other project that wishes to "import" the shared code would perform the necessary renaming. Unfortunately things aren't quite that elegant at the moment. Instead, there is a "core" shared module that contains the real code, and a sub-project for each shared library 'user' that does the renaming. This will hopefully be done away with in the future. For now, you can (mostly) ignore all of the subprojects except the "core" one.
Why not just a normal library?
There are two primary reasons why shared is not just a jarfile that other projects put on their classpath.
Firstly, in order to avoid the "jar hell" described in the above section when multiple projects that use shared are all present in the classpath, a strict binary compatibility rule would need to exist for the shared project. The compatibility would not only need to avoid breaking any APIs, but would also need to ensure that no behaviour changed between releases. That's hard to do. And any mistake could subtly break things making debugging really hard.
Secondly, it would mean that the MyFaces Core releases would be three jars, not two. That is inelegant, and not consistent with Sun's JSF implementation.
Versioning
The shared module has its own version numbers; see the version element in the pom.xml file for the shared module. Note that the shared module version numbers are independent of the version number for the project that uses it (though of course a new "release" of the shared module only occurs when a release of a project that depends on it is performed).
The using project (eg Core or Tomahawk) declares a dependency on a specific version of the shared module. See the pom.xml file for the relevant project to see what version of the shared library it uses.
JSF 1.1 vs JSF 1.2 vs JSF 2.0
There are separate versions of the shared code for JSF 1.1, JSF 1.2 and JSF 2.0. The JSF1.2 branch can use java1.5 features for example.
However some MyFaces projects support both JSF1.1 and JSF1.2 with just one trunk version. In that case, the project declares a dependency on the JSF1.1 version of the shared code.
When applying a patch to either branch of the Shared project, the patch should be evaluated to see whether it is appropriate for applying to the other branch too.
The shared library versions intended for use with JSF 1.1 have version numbers of form "2.x". Releases intended for use with JSF 1.2 have versions of form "3.x". Releases intended for use with JSF 2.0 have versions of form "4.x".
Issues
The unusual approach of "package renaming" does sometimes make life a little more difficult for developers.
In older MyFaces project releases, the -sources jarfiles did not include the renamed source code for the "imported" shared module. This meant that it was impossible to step through some of the code in MyFaces projects. This has been fixed in later releases; the repackaged shared source is found in the sources jar for projects that import the shared project.
Setting breakpoints can also be a little tricky; when debugging tomahawk for example, make sure that a breakpoint set in a class from the shared project is set on the version with package name "org.apache.myfaces.shared_tomahawk"!