Berin,

I felt the urge to let you know the final disposition of my problem, because your help was so invaluable in reaching the solution.

The implementation I cam up with is to still restrict the classloader that I use for my Fortress-based container to *not* load anything other than "system" classes from the parent classloader. I have the webapp thread use the custom classloader to dynamically load and start the thread that starts up the container. The two threads then communicate using a pair of Channels (from Doug Lea's concurrent package), and the Channels are also loaded from the parent class.

BTW, I did believe "Berin is right" even the very first time! Now I have learnt from "Berin, who learnt from smarter people". Thanks a bunch for the insight! FYI, I am part of the team working on the OpenSource Keel Framework (http://www.keelframework.org) which is based on Avalon, not ready for primetime yet...but getting there.

Thanks again!

Shash






From: "Berin Loritsch" <[EMAIL PROTECTED]>
Reply-To: <[EMAIL PROTECTED]>
To: "'Shash Chatterjee'" <[EMAIL PROTECTED]>, "'Avalon Developer's List'" <[EMAIL PROTECTED]>
Subject: RE: Custom ClassLoader with Fortress
Date: Thu, 7 Nov 2002 21:10:16 -0500

> From: Shash Chatterjee [mailto:[EMAIL PROTECTED]]
>
> Berin,
>
> Given what you say, here's what I'll try. Let me know what you think.
> The issue is that, particularly when the Fortress-based
> container will be
> run within a webapp, we were trying to avoid conflicts with
> the versions of
> JARs (Xerces is a good example) that the Webapp in general,
> or even the
> servlet-container, needs versus the one needed for the
> container/server we
> are working on. But I think I can simply set the
> contextClassLoader of a
> Thread, before any of the Avalon/Excalibur classes have been
> instantiated
> and then from that thread use ContextBuilder to create our container.

That is one of the solutions. Another solution is to use a
Servlet container that complies with Servlet 2.4 specifications.
Those mandate that the servlet classloader is isolated from the
server classloader. One example of a compliant container is
Tomcat 4.


> In general, I'm sure this is not an isolated problem for us?
> What is the
> design pattern to use with Fortress when the parent classloader could
> potentially have an incompatible version of a particular lib?

So far, the solution was to separate the classloaders and have
the new classloader load the correct versions of the classes.


> I think I understand the core problem I was having, but let
> me regurgitate
> so you can tell me right or wrong. The problem is not really
> with the
> instance of ThreadSafeCompinentHandler.class that my
> class-loader just
> loaded, but the parameter type instances in the constructor
> are loaded by
> the child loader while those being compared by
> getConstructor() are from the
> parent class-loader. If that's true, then I think I understand!

Not quite--but you are on the right track. Your classloader
defeated the parent classloader mechanism of the URLClassLoader
object. Fortress uses the supplied classloader to load all
classes that it creates. As a result, we had something like
this:

ParentClassLoader:

Had all Avalon stuff

SpecialClassLoader:

Had your components

When Fortress tried to use the SpecialClassLoader to load
Avalon stuff, it either did not find the class, or it loaded
a new copy of the class. Fortress searched the class for
a constructor that matched the set of parameters in the
ComponentHandler interface.

The problem arose because of one fundamental problem with
classloaders:

java.lang.String.class from ClassLoader A
!=
java.lang.String.class from ClassLoader B


To illustrate this point, use a URLClassLoader without any
parent (it will by default use the SystemClassLoader as a
parent) to load an external JAR. Instantiate another to
load the same JAR. Load the same class from both
classloaders, and then compare them with the equals() method.
They are not equal!

public void testClassEquality() throws Exception
{
ClassLoader a =
new URLClassLoader(
new URL[] { new File("sample.jar").toURL() } );
ClassLoader b =
new URLClassLoader(
new URL[] { new File("sample.jar").toURL() } );

Class aClass = a.loadClass( "sample.SomeObject" );
Class bClass = b.loadClass( "sample.SomeObject" );

if ( aClass.equals( bClass ) )
{
System.out.println(
"Berin is wrong and don't listen to him again" );
}
else
{
System.out.println(
"Berin is right, but he learned from smarter people" );
}
}

You should see a message proving that I am right, as long as
there is a file called "sample.jar" with a sample.SomeObject
class in there.

When you remove the hierarchical nature that is part of the
classloader definition, then you don't even have the
SystemClassLoader available to you.


--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

_________________________________________________________________
MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*. http://join.msn.com/?page=features/virus


--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to