https://issues.apache.org/bugzilla/show_bug.cgi?id=47512

           Summary: Binding java.lang.reflect.Proxy to JNDI directory
                    raises java.lang.ClassCastException
           Product: Tomcat 6
           Version: 6.0.18
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
        AssignedTo: dev@tomcat.apache.org
        ReportedBy: mrr...@gmail.com


I've created a custom javax.naming.spi.ObjectFactory that is able to bind
javax.naming.Reference(s) into the global JNDI naming directory during startup
time using a org.apache.catalina.LifecycleListener.

I want two separate web contexts invoke the custom
ObjectFactory#getObjectInstance method indirectly, getting through the local to
the global JNDI context with a ResourceLink by invoking the local
InitialContext#lookup method. Since both contexts have different classloaders
my intention is to create a java.lang.reflect.Proxy given the current thread
classloader.

For the first web context, everything goes Ok. The thread reaches the
ObjectFactory, the object factory peeks the current thread classloader (always
a webapp classloader), peeks the name of the interface to use for
Proxy#newProxyInstance method, and the object to proxify for an internal
collection and returns the proxy.

The problem arises for the second web context. The InitialContext#lookup method
resolves the name and, although the thread never reaches the ObjectFactory, the
object is resolved. Surprisingly, the returned object is the proxy created for
the first web context. This proxy implements an interface available in the
first web context's classloader. This interface is present in the second
context classpath, but is loaded by a different webapp classloader. Thus, a
java.lang.ClassCastException is raised.

Digging into the tomcat codebase, I found in org.apache.naming.NamingContext
that once a reference is resolved, the resolved object is sort of rebound to
the original name. Thus, when the second lookup invocation arrives, the name is
associated to an object (not a reference) and the ObjectFactory is never
invoked.

Here's the org.apache.naming.NamingContext code, lines 791 to 799:

 } else if (entry.type == NamingEntry.REFERENCE) {
       try {
          Object obj = NamingManager.getObjectInstance(entry.value, name, this,
env);
             if (obj != null) {
               entry.value = obj;
               entry.type = NamingEntry.ENTRY;
             }
          return obj;

When a NamingEntry.REFERENCE arrive, the reference is resolved with the help of
a javax.naming.spi.NamingManager. If the resolved object is null, the entry is
converted to a NamingEntry.ENTRY instead of leaving it as a
NamingEntry.REFERENCE.

In my opinion, the entry should be left as a REFERENCE, so the next invocation
to the method, no matter who is the invoker nor its classloader, resolves the
reference again with the javax.naming.spi.NamingManager's help. This "cache"
policy of references should be left to the ObjectFactory itself, which will
have all the necessary information to apply such a policy.

The code change would only imply the removal of the if I've shown above.

Regards,

Martin.

-- 
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to