On 13 Jan 2006, at 13:10, Cyrus Daboo wrote:
The text filter is very specific to the webapp (it does some custom
indexing of the iCalendar data - not a straight text extraction as
other text filters do) and it has a dependency on iCalendar
libraries for parsing. Thus a whole bunch of stuff, not just the
text filter, would have to be moved up to the tomcat class loader -
this seems like a bad layering violation to me.
It is - but the problem is more fundamental.
Fundamentally, you've got two paths you'll end up on:
1) You keep the core outside the war classloader, and the filter in
the system classloader. Because the core application is using shared
classes, references to classes that aren't available in the WAR
classlaoder is available to other WARs - however, they are invalid
when used there. Keep it in the WAR classloader, and you risk
creating a dirty environment for other WARs.
2) You move the core into the WAR with the rest of it - but now you
need to ensure that your shutdown hooks are getting called by the war
to shut down the environment properly. You can either use HiveMind
or some other dependency injection system to perform the shutdown on
registry shutdown (and call shutdown from a filter, for example) or
use one of the servlet unloads to do so. But now you can't share
anything between instances, and nothing's visible to other
applications, some of which may be SSO.
There's no good way around this - we have the same problem in the
Castor project; when the core is loaded from common, classes loaded
into it become a part of the system that's visible, if someone tries
hard enough, to other classloaders in other wars, and do cause
layering violations.
There's a design-around, I guess, though: Ensuring that all access
to the core is done through a 'context', and the context retains all
of the classloaded filters, etc.; releasing that context can then
release the classloader-dependent, environment-specific stuff, while
preventing the layering problems. On the other hand this, by design,
prevents transparent sharing of the global context, as a global
context no longer exists - applications are responsible for knowing
when a context is shareable based on the stuff that's loaded into it
and their own use of the context.
If you won't move to 2), you have to make 1) tenable - that means
that when your application shuts down, you need to find a way to
basically either unregister everything you registered which was war-
specific, or return the system to (either an initialized or a
shutdown) state where none of those classes are loaded.
Not uncommon, no - but not easily avoidable when people violate the
layering by passing class implementations in the war out to something
that runs, and continues to run beyond the war's unload, in a set of
other threads. Ultimately, the WAR was responsible for creating the
layering violation - it's the WAR's job of doing whatever's necessary
to make unload possible.
That may mean API for de-registering the stuff you've added, or it
may mean forcing a shutdown of the jackrabbit container. Them's the
breaks.