commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Keith Naas" <kn...@netjets.com>
Subject Re: logging: more then one version of 'org.apache.commons.logging.Log'
Date Wed, 09 Nov 2005 14:17:25 GMT

I apologize for the length of this message.  We are encountering the
exact same problem as had been mentioned by Kurt.  However, it is
occuring within a WebLogic 8.1 SP2 container.  We know exactly what
tickles the and we have identified the code in Commons-Logging that may
be the cause.  FYI: WL uses a parent-first classloader.

Issue:

We have an enterprise application that contains many different web app
and ejb modules.  The ear contains a single commons-logging library and
a single log4j library.  It makes use of another enterprise application
that also contains many different web app and ejb modules.  We are using
distributed transactions to tie together transactions between two
different enterprise applications.  We are using Hibernate3.0.5 as our
persistence layer.  We are using commons-logging 1.0.4 and log4j 1.2.8.

A method in EAR1.EJBModuleA with a "Required" TxAttribute calls a method
in EAR2.EJBModuleB with a "Required" TxAttribute.

Just before the transaction is completed by the container, we receive a

org.apache.commons.logging.LogConfigurationException:
org.apache.commons.logging.LogConfigurationException: Invalid class
loader hierarchy.  You have more than one version of
'org.apache.commons.logging.Log' visible, which is not allowed. (Caused
by org.apache.commons.logging.LogConfigurationException: Invalid class
loader hierarchy.  You have more than one version of
'org.apache.commons.logging.Log' visible, which is not allowed.)

Bizarrely If we change the TxAttribute in EAR1.EJBModuleA to "Supports",
the issue does not occur.

We did some investigation into the hibernate & commons-logging code and
we found that the LogFactoryImpl in commons-logging is loading the Log
interface using a different classloader than the Logger implementation.
This is easy to see by adding the following code to the top of the
getLogConstructor() method.

            final ClassLoader cl1 = this.getClass().getClassLoader();
            final ClassLoader cl2 = this.getContextClassLoader();
            String logInterfaceName = LOG_INTERFACE;
            java.util.Enumeration enumeration =
cl1.getResources(logInterfaceName.replace('.', '/') + ".class");
            while (enumeration.hasMoreElements())
            {
                System.out.println(logInterfaceName + ":" +
enumeration.nextElement());
            }
            enumeration = cl2.getResources(logClassName.replace('.',
'/') + ".class");
            while (enumeration.hasMoreElements())
            {
                System.out.println(logClassName + ":" +
enumeration.nextElement());
            }  

The printout looks something like this:

org.apache.commons.logging.Log:zip:EAR2......logging/Log.class
org.apache.commons.logging.impl.Log4JLogger:zip:EAR1.......impl/Log4JLog
ger.class

Classes loaded by two different ClassLoaders are not considered
identical.  Since EAR1 and EAR2 have two different ClassLoaders, there
is no isa relationship between the EAR1 Log4JLogger implementation and
the EAR2 Log interface.

Question:

The LogFactoryImpl loads the interface on the ClassLoader from
LogFactoryImpl.getClass().getClassLoader().  However, it loads the
implementation on the Thread.currentThread().getClassLoader().  Why does
it use two different ClassLoaders instead of loading both the interface
& implementation on the same ClassLoader? 

Thanks for any help,
Keith Naas
Sr. Developer
NetJets, Inc.
898-3044 x4105



**********
This message contains information which may be confidential and privileged. Unless you are
the addressee (or authorized to receive for the addressee), you may not use, copy or disclose
to anyone the message or any information contained in the message. If you have received the
message in error,  please advise the sender by reply e-mail and delete the message.
Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message