Application Libraries - Part II Semantics
By aseembajaj on Nov 20, 2008
(Migrated from Rob Woollen's blog on dev2dev with his permission. This entry was originally posted on August 08, 2005 11:29 AM)
Designing large software features like application libraries is always an interesting challenge. While it wasn't initially a stated goal, in retrospect the design was heavily influenced by a desire to minimize the implementation work. I'm certainly not trying to imply the development team was lazy, but minimizing new concepts became the best means to achieve our main design goals:
- Address customer use cases, specifically separately packaged code libraries potentially shared between many applications and versioned independently.
- Make it easily possible to port library-based applications to earlier WLS releases or other J2EE servers.
- Ensure libraries are easily understood and require limited change to existing applications.
- Provide equivalent deployment, versioning, and management functionality as non-library applications.
I'd really like to emphasize the second point here. While libraries are an innovative feature only in our application server, they aren't meant to lock developers into 9.0. The design strives to make it easy and natural to port library-based applications to older WLS releases or other J2EE servers which don't support this concept.
With those goals in mind, the design that evolved was simply that library applications have the same semantics as if they were deployed together as a single EAR file. Internally the server runs through a series of steps as applications are deployed on the target server. During an early stage in deployment, it establishes which modules are in an application and instantiates containers for each. These might be ejb or web modules declared directly in the
application.xml, or they may be imported from a library. The only real difference is the path on disk to the module.
The vital piece to understand is that libraries only change the path where classes and resources are loaded. After the container is created, all semantic behavior is exactly as if everything was within a single EAR file. The classloading, management, console pages etc are all the same. Libraries are merely a packaging concept.
Libraries can be either java classes, a single component (eg a war or ejb-jar), or an EAR file with 1 or more components. In the java class case, the server just adds the jar file to the application's classloader. The single component case is essentially adding a new module entry to the application.xml with a different relative path to the ejb-jar or webapp.
EAR libraries are a slightly more complicated case since the library has its own application.xml and weblogic-application.xml. The server handles this by merging the library's application.xml with the application.xml in the application. The merge is relatively straightforward, but it should be noted that the application's descriptor takes precedence on any conflict. For instance, if you had the same ejb module (same uri) in both the library and the application, the application's version would be used. (I included this information for completeness, but I would recommend that applications not override library modules. If this is necessary, I would suggest repackaging the library as needed.)
Another main design issue was the semantics when multiple applications reference the same library. One option is to have a single library instance shared by all referencing applications. This has some classloader advantages, but it makes redeploying the applications and libraries significantly more complicated. The design instead favored the simpler and more flexible approach where each application included its own library component copy. This approach's advantages may become clearer in the next blog entry which discusses versioning, upgrades, and how to undeploy a library.
WLS 9 includes a tool weblogic.appmerge (run java weblogic.appmerge to see usage) which given an application and 1 or more libraries produces a single, merged EAR file. The tool's merge process shares the same code with the server, but instead of merging data structures in memory, it writes the output to disk. The appmerge tool can be used to debug or better understand how libraries work, but it also allows porting to other servers or older WLS releases.
I hope this blog entry provided further insight into Application Libraries. In my next entry, I'll cover how libraries are versioned, deployed/undeployed, and zero downtime library upgrades. Please post a comment if there's anything that is unclear or suggestions on further topics.