On Wed, 22 Jan 2003, Jeff wrote:
> Date: Wed, 22 Jan 2003 10:47:27 -0500 > From: Jeff <[EMAIL PROTECTED]> > Reply-To: Struts Users Mailing List <[EMAIL PROTECTED]> > To: [EMAIL PROTECTED] > Subject: Struts-extending classes with static variables shared by webapps > in different contexts > > SCENARIO: > > * one running instance of Tomcat, whose $CATALINA_HOME is c:/tomcat > > * multiple Struts-using webapps, each developed separately using > Netbeans or Forte, autodeployed into that one instance of Tomcat via > .war files copied to c:/tomcat/webapps. > > * ALL classes needed by the webapp and developed by me are in its > respective WEB-INF/classes or libs directory, and ABSENT from any > location common to all webapps running under that instance of Tomcat > ($JAVA_HOME/jre/lib/ext, $CATALINA_HOME/common, $CATALINA_HOME/shared, > etc) > > * Instead of Action, all of the webapps use com.foo.MyAction, which > extends Action. Each webapp has its own copy of MyAction.class in its > respective WEB-INF/classes/com/foo directory, as well as its own copy of > the Struts jarfiles in WEB-INF/libs (which probably gets unwrapped and > repackaged by Netbeans/Forte when it creates the .warfile) > This is all goodness, but with a potential caveat -- Tomcat has copies of commones-{collections,dbcp,pool} in its common/lib directory, so watch out for sharing problems on classes from these packages. > And now, where things potentially get ugly... > > * MyAction has a few static class variables that get treated like > site-wide global constants. It assumes that NO OTHER WEBAPP running in a > different context path of the same Tomcat instance can/will ever see > them. Tomcat's class loader architecture is documented: http://jakarta.apache.org/tomcat/tomcat-4.1-doc/class-loader-howto.html The fact that each webapp has a separate class loader (loading things from /WEB-INF/classes and /WEB-INF/lib) is portable. Anything above that in the diagram is not, although most containers offer something similar. Static variables are only global to the class loader that loaded the containing class, plus any class loaders for which this is the parent. Therefore, a static variable in a class loaded from the webapp class loader will be global only to that webapp. > Is this a valid assumption? Do the relevant specs for Servlets, webapps, > and/or Java classloading GUARANTEE that each context is a sandboxed > private universe relative to all other webapps running on the machine > (at least insofar as classes loaded from WEB-INF/classes or WEB-INF/libs > are concerned), Yes. > or would a servlet container and/or JVM be perfectly > within its rights to examine MyAction.class, determine that two or more > of the webapps are really using the exact same class, and share a single > initialized class among ALL of them (with catastrophic results)? Not allowed. > > I'm slightly paranoid, because I vaguely remember having a problem with > this exact issue last February/March. I don't remember exactly, but I > was using some 4.0 release of Tomcat 4, 1.4.0_x j2sdk, and the last > stable daily build (circa mid-January 2002, I believe) of Struts > available before 1.1b1 officially came out. The good news is that I > haven't been able to replicate what I think I remember happening with > Tomcat 4.1.18, j2sdk 1.4.1_03, and Struts 1.1b2, but I'm not sure > whether that's due to random good luck at the moment, or whether it's > The Way Things Are Supposed To Work (but Possibly Didn't last year). > I'll admit that any problem I might have had last year might have been > due to some other issue entirely (I knew a LOT less about Struts, and > Tomcat for that matter, than I do now, and might very well have > misconfigured something else so badly that it caused it instead, or > badly misinterpreted what I thought I was seeing). > > So... is it OK to use static class variables in classes extending > Struts' Action class as site-wide global constants, or is it a Bad > Thing, or maybe even Utterly Taboo? The first problem people have with class loaders are generally related to trying to share things that should not be shared. For example, trying to share struts.jar itself (in 1.0.2) is a total waste of time -- Struts itself used static variables that should not be shared. (There are other problems with this too -- you'll get ClassNotFoundExceptions on classes that Struts tries to load from the webapp. (Struts 1.1 has experimental support for being able to share struts.jar, but it's not a supported configuration -- you're on your own for figuring out problems.) The second problem people have with class loaders is they try to put JAR files in the "system extensions" directory of their JVM ($JAVA_HOME/jre/lib/ext), to avoid having to manipulate the classpath variable. In general, this is a very bad idea because it messes up the class loader that these classes are loaded from. If you're a editor+Ant developer like me, my advice is to leave CLASSPATH unset, use your Ant build scripts to create compile classpaths as needed, and put all the JAR files you need inside the webapp. That way, you'll have minimal problems with classes being shared when you don't expect them to be, as well as unexpected class not found problems. Craig -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>