You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Johan Eltes <jo...@callista.se> on 2002/11/25 22:38:35 UTC

J2EE-kompliant class loading

Hi!

Are there any plans to change the class loading (or more generally, loading
resources through class loaders) in struts to be J2EE compliant?
I here the frustration from many developers getting the infamous
ClassNotFoundException when they use standard J2EE deployment of classes.

The only supported scenario for Struts seem to be:

Ear>
...War1>WEB-INF>lib>struts.jar
..............>classes>my.subclass.of.struts.action.class
...War2>WEB-INF>lib>struts.jar
..............>classes>my.subclass.of.struts.action.class

Typically, an enterprise application uses dependent jars, to avoid multiple
copies of the same library. In addition, there is often a need to implement
a generic, but yet application specific abstract subclass of the struts
Action class. Such generic application classes used to be deployed in a
dedeicated dependent jar, referenced (e.g. by inheritence) from various
UI-specif classes hosted in various Web-apps:

Ear>
....struts.jar (dep. jar)
....myframwork_with_myactionbase.jar (dep. jar)
....War1>WEB-INF>classes>my.first.subclass.of.MyActionBase.class
........>META-INF>MANIFEST.MF (with Class-Path entry referencing dep.jars)
....War2>WEB-INF>classes>my.second.subclass.of.MyActionBase.class
........>META-INF>MANIFEST.MF (with Class-Path entry referencing dep.jars)

However, Struts can not be deployed as a dependent jar, since struts loads
classes (Action-classes and Actionform classes) through the application
class loader instead of the thread context class loader. The J2EE spec
indicates that the thread context class loader should be used for class
loading. 

I patched struts to use the thread context class loader - and voala - all
class loading issues where gone. The scenario above ran like a charm, as
expected. 

I often use Tomcat for development and various J2EE servers for deployment.
It seems that Tomcat (when run standalone) does not set up a proper thread
context class loader. For struts to run well in Both Tomcat and in a J2EE
environment, Struts could use a strategy to first load resources through the
thread context class loader and then try the application class loader as a
fallback, in case resources are not found. It used the following helper
class to patch struts. The patched version runs well in both J2EE servers
and Tomcat standalone. I replaced all calls to

Class.forName(String name)
with a call to
ClassLoaderHelper.classForName(String name)

I didn't (but should) patch the class to resource bundles.

Is this planned to be fixed in struts 1.1?

/johan

public class ClassLoaderHelper {
  public static Class classForName(String className) throws
ClassNotFoundException {
    try {
      return Class.forName(className,true,getThreadContextClassLoader());
    }
    catch (ClassNotFoundException cnfe) {
      return Class.forName(className,true,getClassLoader());
    }
  }

  public static InputStream getResource(String name) {
    InputStream resource =
getThreadContextClassLoader().getResourceAsStream(name);
    if (resource == null) {
      return getClassLoader().getResourceAsStream(name);
    } else return resource;
  }

  public static ClassLoader getThreadContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
  }

  public static ClassLoader getClassLoader() {
    return ClassLoaderHelper.class.getClassLoader();
  }
}


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: J2EE-kompliant class loading

Posted by Johan Eltes <jo...@callista.se>.
Thanks.
I'm looking forward to start using 1.1.

> 
> If I were the admin of an app server like this, you'd have to seriously
> twist my arm to put struts.jar in a shared repository.  To me, the pain is
> not worth the gain.
>

To me, there is a significan't differense in putting struts.jar in a shared
repository on the app server level versus having it as a dependent jar
within an enterprise application archive. The concept of dependent jars
within the J2EE spec was specifically designed to remove the need for
complex build scripts that copies all shared jars into every j2ee component
and yet keeps autonomicity at the enterprise archive level. My intention was
not to argue about the validity of this mechanism. It's there and should be
supported by frameworks intended to be used in J2EE environment. Although I
can see the point in keeping autonomicity at the war level, many, many
developers are happy keeping it at the ear level.

/Johan 


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: J2EE-compliant class loading

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Tue, 26 Nov 2002, Johan Eltes wrote:

> Date: Tue, 26 Nov 2002 07:15:14 +0100
> From: Johan Eltes <jo...@callista.se>
> Reply-To: Struts Users Mailing List <st...@jakarta.apache.org>
> To: Struts Users Mailing List <st...@jakarta.apache.org>
> Subject: Re: J2EE-compliant class loading
>
> Den 02-11-26 00.47, skrev "Craig R. McClanahan" <cr...@apache.org>:
>
> >
> > IMHO, however, sharing JAR files has a very serious drawback, IMHO -- it
> > *forces* a cross dependency between webapps that is not otherwise
> > necessary.  Web appliations should be designed to be as completely
> > independent of each other as possible, so that you can do things like
> > upgrade the Struts version in a suite of apps one application at a time,
> > without forcing them to *all* be upgraded at once.
> >
>
> I'm not sure it is valid to assume that multiple wars within an ear could
> use different versions of struts on their respective WEB-INF/lib. The J2EE
> spec (1.3) states:
>
> "There must be only one version of each class in an application. If one
> component depends on one version of an optional package, and another
> component depends on another version, it may not be possible to deploy an
> Application Assembly application containing both components. A J2EE
> application should not assume that each component is loaded in a separate
> class loader and has a separate namespace."
>

You might want to review section 9 of the Servlet Spec, which (among other
things) specifically describes the class loader that a servlet container
(in a J2EE server or not doesn't matter) is required to provide to each
web application.

> /johan

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: J2EE-compliant class loading

Posted by Johan Eltes <jo...@callista.se>.
Den 02-11-26 00.47, skrev "Craig R. McClanahan" <cr...@apache.org>:

> 
> IMHO, however, sharing JAR files has a very serious drawback, IMHO -- it
> *forces* a cross dependency between webapps that is not otherwise
> necessary.  Web appliations should be designed to be as completely
> independent of each other as possible, so that you can do things like
> upgrade the Struts version in a suite of apps one application at a time,
> without forcing them to *all* be upgraded at once.
>

I'm not sure it is valid to assume that multiple wars within an ear could
use different versions of struts on their respective WEB-INF/lib. The J2EE
spec (1.3) states:

"There must be only one version of each class in an application. If one
component depends on one version of an optional package, and another
component depends on another version, it may not be possible to deploy an
Application Assembly application containing both components. A J2EE
application should not assume that each component is loaded in a separate
class loader and has a separate namespace."

/johan


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: J2EE-kompliant class loading

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Mon, 25 Nov 2002, Johan Eltes wrote:

> Date: Mon, 25 Nov 2002 22:38:35 +0100
> From: Johan Eltes <jo...@callista.se>
> Reply-To: Struts Users Mailing List <st...@jakarta.apache.org>
> To: struts-user@jakarta.apache.org
> Subject: J2EE-kompliant class loading
>
> Hi!
>
> Are there any plans to change the class loading (or more generally, loading
> resources through class loaders) in struts to be J2EE compliant?
> I here the frustration from many developers getting the infamous
> ClassNotFoundException when they use standard J2EE deployment of classes.
>

Since Struts defines zero class loaders of its own, and already uses the
standard conventions and mechanisms for multiple class loaders, it is
already compliant with J2EE specs.

> The only supported scenario for Struts seem to be:
>
> Ear>
> ...War1>WEB-INF>lib>struts.jar
> ..............>classes>my.subclass.of.struts.action.class
> ...War2>WEB-INF>lib>struts.jar
> ..............>classes>my.subclass.of.struts.action.class
>

This is indeed the case for Struts 1.0.x.  For Struts 1.1.x, you *should*
be able to put struts.jar itself in a shared parent classloader (i.e. for
Tomcat, into the common/lib directory).  I can't guarantee that all
possible corner cases have been tested, but the basics certainly work.

> Typically, an enterprise application uses dependent jars, to avoid multiple
> copies of the same library. In addition, there is often a need to implement
> a generic, but yet application specific abstract subclass of the struts
> Action class. Such generic application classes used to be deployed in a
> dedeicated dependent jar, referenced (e.g. by inheritence) from various
> UI-specif classes hosted in various Web-apps:
>
> Ear>
> ....struts.jar (dep. jar)
> ....myframwork_with_myactionbase.jar (dep. jar)
> ....War1>WEB-INF>classes>my.first.subclass.of.MyActionBase.class
> ........>META-INF>MANIFEST.MF (with Class-Path entry referencing dep.jars)
> ....War2>WEB-INF>classes>my.second.subclass.of.MyActionBase.class
> ........>META-INF>MANIFEST.MF (with Class-Path entry referencing dep.jars)
>
> However, Struts can not be deployed as a dependent jar, since struts loads
> classes (Action-classes and Actionform classes) through the application
> class loader instead of the thread context class loader. The J2EE spec
> indicates that the thread context class loader should be used for class
> loading.
>
> I patched struts to use the thread context class loader - and voala - all
> class loading issues where gone. The scenario above ran like a charm, as
> expected.
>

Or just use 1.1 and you don't have to patch anything.

> I often use Tomcat for development and various J2EE servers for deployment.
> It seems that Tomcat (when run standalone) does not set up a proper thread
> context class loader. For struts to run well in Both Tomcat and in a J2EE
> environment, Struts could use a strategy to first load resources through the
> thread context class loader and then try the application class loader as a
> fallback, in case resources are not found. It used the following helper
> class to patch struts. The patched version runs well in both J2EE servers
> and Tomcat standalone. I replaced all calls to
>
> Class.forName(String name)
> with a call to
> ClassLoaderHelper.classForName(String name)
>
> I didn't (but should) patch the class to resource bundles.
>
> Is this planned to be fixed in struts 1.1?
>

Already done.

IMHO, however, sharing JAR files has a very serious drawback, IMHO -- it
*forces* a cross dependency between webapps that is not otherwise
necessary.  Web appliations should be designed to be as completely
independent of each other as possible, so that you can do things like
upgrade the Struts version in a suite of apps one application at a time,
without forcing them to *all* be upgraded at once.

The disk space cost of this approach is trivial.  The management effort is
minimal (but it enables you to use different versions as needed).  The
memory space cost is real, but insignificant unless there are very large
numbers of applications involved.

If I were the admin of an app server like this, you'd have to seriously
twist my arm to put struts.jar in a shared repository.  To me, the pain is
not worth the gain.

> /johan
>

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>