RE: Tomcat 3.2, RMI, JNDI Classloaders: a solution

2001-03-15 Thread Andrew Gilbert

Carlos,

Thanks. This is interesting. Can you explain what the effect of
Thread.setContextClassLoader() is? Does it make classes from the
WEB-INF/lib and WEB-INF/classes area avaiable to classes loaded by 
the boot class or system class loader?

Andrew

-Original Message-
From: Carlos Pita [mailto:[EMAIL PROTECTED]]
Sent: Thursday, March 15, 2001 3:50 AM
To: [EMAIL PROTECTED]; [EMAIL PROTECTED];
[EMAIL PROTECTED]; [EMAIL PROTECTED];
[EMAIL PROTECTED]
Subject: Tomcat 3.2, RMI, JNDI  Classloaders: a solution


Hi all!

A lot of people has been having problems with Tomcat 3.2,
classloaders,
jndi, jndi.properties, rmi and stubs when trying to call ejbs from
Tomcat in
a different JVM. The problem is simple: because jndi and rmi classes are
loaded by the system (or bootstrap, I can't remember it but it really
doesn't matters) classloader -see
jdk1.3\docs\tooldocs\findingclasses.html - they can not see the
resources
and classes of your context (loaded by the context classloader, which is
a
descendant -i mean in the classloader delegation hierarchy- of the
system
classloader).
An obvious and bad solution is to put your classes in the CLASSPATH
(don't do this!) to allow them to be loaded once for all of your
contexts by
the system classloader.
Instead, to fix the problem you should add the request interceptor
showed below to your server.xml (I have read an email saying that it
should
be the last request interceptor in the chain so I put it the last, but I
haven't tried with another combinations):

RequestInterceptor
 className="org.apache.tomcat.request.Jdk12Interceptor" /

This is in order to call the Thread.setContextClassLoader() during
each
request. The following is taken from a post by C. McClanahan in
tomcat-user:
"Note that Tomcat 4.0, because it is guaranteed a Java2 platform as a
prerequisite, calls Thread.setContextClassLoader() on every request by
default".
But even after doing this, jndi.properties in your WEB-INF/classes
(or
in a .jar in WEB-INF/lib) won't be loaded. Keep reading the following
paragraphs quoted from an email by Christopher Audley in tomcat-dev!

""
The following discussion applies to tomcat 3.2.1 running under Sun JDK
1.3

I spent this afternoon tracking down why a call to new InitialContext()
from a web application did not appear to be finding the jndi.properties
located under WEB-INF/classes.  I am using the Jdk12Interceptor and
verified that Thread.currentThread().getClassLoader() was the tomcat
AdaptiveClassLoader before the call to new InitialContext().  After some
investigation I determined that the JNDI implementation uses the
classloader method getResources to find all occurances of the file
jndi.properties in the classpath.  AdaptiveClassLoader does not have
this method implemented, the default implementation calls findResources
which simply returns an empty Enumeration unless overriden.

Attached are patches to AdaptiveClassLoader and ClassRepository to
implement findResources so that JNDI will behave correctly when a
jndi.properties is placed in the web application classpath.  I have
moved some code from AdaptiveClassLoader to ClassRepository to avoid
code duplication and changed the implementation of getResource to
findResource for consistency.

I hope that this can be incorporated into the sources before 3.2.2.
""

Finally, after aplying the patch (I've attached it as you can see)
and
recompiling the sources you get the desired behaviour.

See you,
Carlos



RE: Tomcat 3.2, RMI, JNDI Classloaders: a solution

2001-03-15 Thread Craig R. McClanahan



On Thu, 15 Mar 2001, Andrew Gilbert wrote:

 Carlos,
 
 Thanks. This is interesting. Can you explain what the effect of
 Thread.setContextClassLoader() is? Does it make classes from the
 WEB-INF/lib and WEB-INF/classes area avaiable to classes loaded by 
 the boot class or system class loader?
 

You can make them visible, but the class from the boot classloader or
system classloader has to know what to do -- it calls
Thread.getContextClassLoader() to get the class loader for the current
thread, and asks *that* classloader to create the new object, instead of
using the "new" operator.

WARNING:  Thread.setContextClassLoader() does not exist in JDK 1.1 (which
Tomcat 3.x is designed to support), so this change can only be added to
optional Tomcat components that are loaded only when running in a Java2
environment.

WARNING:  Tomcat 4.0 (which requires Java2 already) does use the context
class loader in this manner already.  However, this behavior is *not* in
the servlet specification, and you can *not* rely on it if your
application needs to be portable.  (For that matter, servlet containers
are not even required to provide a "shared JAR files" mechanism -- they
are only required to support WEB-INF/classes and WEB-INF/lib.)

 Andrew
 

Craig McClanahan




RE: Tomcat 3.2, RMI, JNDI Classloaders: a solution

2001-03-15 Thread Andrew Gilbert


You can make them visible, but the class from the boot classloader or
system classloader has to know what to do -- it calls
Thread.getContextClassLoader() to get the class loader for the current
thread, and asks *that* classloader to create the new object, instead
of
using the "new" operator.

As an example then, Toolkit.getDefaultToolkit() does a Class.forName and
if that fails tries the system class loader when creating the default
AWT toolkit. I would assume then that the jdk12 interceptor is not going
to help in a scenario such as using PJA where one has to force pja.jar
into the boot class path. Is that correct?