Simon Kitching wrote:
I don't claim to be an expert on any of this and I have not followed all of the JCL and BeanUtils threads, so take these as comments from the peanut gallery. I like the idea in the proposal, but I am not sure that the specific application is separating concerns correctly. Maybe answering the questions below will help me understand what is going on.Hi All,
After working on issues in commons-beanutils and commons-logging linked to behaviour within j2ee-style environments, I've come to the conclusion that there is currently *no* way to correctly implement the Singleton pattern within code that might be deployed in a j2ee-style environment.
This is rather disconcerting.
I believe there is a way, though, that the standard Java library could be enhanced to make this possible. In other words, a proposal would need to be submitted as an enhancement to java via the Java Community Process. Could people please have a look at this and tell me whether they think I'm right or that they think I'm nuts?
The doc is here: http://www.apache.org/~skitching/ContextClassLoaderLocal.html
The doc and your previous posts refer to "deployment" and "undeployment" as the events leading to initialization and cleanup. This sounds funny to me, because these are relatively rare events - when new or modified components are deployed to the server or components are removed. I assume that what you really mean is container startup / shutdown events. Am I correct here?
Assuming startup/shutdown is what we need to worry about, then whether we have a problem, and what kind it is, depends on whether the initialization and cleanup activities can be triggered by J2EE component lifecycle events. As Craig pointed out, web application shutdown can be detected by a ServletContextListener. Individual servlets get destroy() events when they are unloaded and EJBs also get lifecycle events. Where do the things that we need to worry about "live" in J2EE applications and why can't they just expose management APIs that get trigerred by J2EE component lifecycle events? This is probably where I am not understanding the problem. Could it be that part of the problem has to do with container code itself (i.e, the thingies spawning singletons are used by the containers directly)?
I can see the general value of the ContextClassLoaderLocal concept, but I am not sure that for things like BeanUtils instance isolation in J2EE containers this is the best way to go. What I am struggling with is why in a J2EE container environment we would not just use JNDI or servlet- or EJB-local references to house the singletons and lifecycle events to initialize and clean them up. Perhaps ironically, under the covers tomcat's JNDI provider maps JNDI contexts to classloaders. Seems to me that the web app developer should be thinking about the JNDI context, not the classloader. I understand that BeanUtils is trying to make things easier for web app developers by hardwiring the mapping for them, but somehow that just doesn't seem right to me. What am I missing?
Phil
==
I've also been pondering the idea of a commons-singleton project. The approach would be to provide something like the following. Note that I haven't put a *whole* lot of analysis into this idea yet, and there might be some fatal flaw. I'm only posting this idea now because we're actively discussing related topics for commons-logging 1.0.5 and I'll be away for the next three weeks.
public class org.apache.commons.singleton.Singleton {
/**
* Provide an algorithm for correctly storing and retrieving
* Singleton objects. Applications running in different environments
* (eg different j2ee containers) may need to use different approaches
* to correctly implement the Singleton pattern. If a strategy is
* set here, then it is used when the getSingleton and setSingleton
* methods of this class are invoked. * <p>
* If this method is not called (or null is passed), then this class
* will try to guess an appropriate strategy for storing Singletons.
*/
public void setSingletonStrategy(SingletonStrategy s);
/** * Return an instance of the specified class which is unique to * the current webapp. */ public Object getSingleton(Class c);
/**
* Save the specified object instance as the singleton instance
* for the specified class. *
* It is expected that "o instanceof c" is true.
*/
public void setSingleton(Object o, Class c);
}
The get/set singleton code would try to determine the correct way of saving a singleton using something like the following algorithm. Note that the o.a.c.s.Singleton class might have been loaded by a child or shared classloader.
* if a strategy has been set, use it.
* if Thread.currentThread.getContextClassLoader returns the same
object as ClassLoader.getSystemClassLoader, then we are running
in a plain app environment (not a j2ee or similar environment), so just store the singleton in a Map which is a static member of
this class.
* if Thread.currentThread.getContextClassLoader() returns an object
which implements "ContextClassLoaderLocal" then store the singleton
against that classloader (see the proposal above for adding this
functionality to java core).
* try various container-specific mechanisms for registering an
"undeploy" of the context classloader. If it *is* possible to somehow
get notification of undeploy of the component whose classloader is
Thread.currentThread().getContextClassLoader(), then simply add an
entry to a static map keyed by the current context-classloader, and
ensure that when that context-classloader is undeployed the map entry
is cleared.
* throw an exception. This ensures that an app that uses singletons
fails visibly rather than silently fails to work correctly. The
deployer is then forced to provide an explicit singleton storage
strategy.
Note that if all commons libraries that need singletons were to use this common o.a.c.singleton.Singleton class, then users would need to configure a singleton storage strategy only once.
Thanks,
Simon
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
