Environment: commons-logging-1.0.2.jar log4j-1.2.6.jar Apache Tomcat/4.1.12-LE-jdk14 Situation: I have my own realm implementation that is stable in Tomcat 4.0.3-LE, and I'm moving up to 4.1.12. In addition, I am also moving all of my codebase to the commons-logging package. After moving to commons-logging, everything in my codebase works in a simple JVM, i.e. JUnit tests and Java Applications. When this is inside the tomcat classloader heirarchy though, NOTHING works. Each of the following scenarios describe the things I've done, with somewhat different results, but all leading back to incompatible class loading schemes. Is there a tomcat bug? The first scenario describes a situation where a server realm component is finding the log4j classes using the method from the LogFactoryImpl.isLog4JAvailable() method...it returns 'true' when the log4j classes ARE NOT in the server/lib, but all the way down in one of my webapp/lib. I believe this is a tomcat issue. ============================================== This scenario is debug output I placed in the methods that the LogFactory uses to determine if log4j is available. I copied loadClass(), isLog4JAvailable(), getContextClassLoader() from the LogFactory and LogFactoryImpl into my Realm, and here is the output when I put log4j.jar in my 'operations' webapp and made sure that the log4j.jar is not available anywhere else in the tomcat heirarchy: ->loadClass(org.apache.log4j.Category) ->trying the context classloader from Thread.getContextClassLoader() ->got the context classloader from Thread.getContextClassLoader() ->contextClassLoader worked. returning class org.apache.log4j.Category ->trying Class.forName(org.apache.log4j.Category) ->Class.forName RETURNING an exception. ****isLog4JAvailable(): true This should be false! Why should a server component be able to access my webapp's jars??? Is the commons-logging package unsafely assuming how a classloader will work, or is the Tomcat-Catalina configuration of tiered classloaders incorrectly allowing access to that class via the thread context classLoader? Nonetheless, even if the tomcat class loader isn't doing it's job exactly, the commons-logging package tests for that class via the contextClassLoader, but it then cannot instantiate the class. That would mean that it's not using the context class loader to instantiate...wouldn't it? If so, that is inconsistent as well.
============================================== When I put the log4j-1.2.6.jar in with the latest commons-logging-1.0.2.jar in catalina\server\lib: Using CATALINA_BASE: .. Using CATALINA_HOME: .. Using CATALINA_TMPDIR: ..\temp Using JAVA_HOME: C:\Development\lib\jdk\j2sdk1.4.0 Exception during startup processing java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.jav a:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessor Impl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:203) Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Layout at org.apache.commons.logging.impl.Log4jFactory.getInstance(Log4jFactory.ja va:153) at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImp l.java:285) at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:409) at org.apache.commons.digester.Digester.<init>(Digester.java:281) at org.apache.catalina.startup.Catalina.createStartDigester(Catalina.java:2 80) at org.apache.catalina.startup.Catalina.start(Catalina.java:441) at org.apache.catalina.startup.Catalina.execute(Catalina.java:400) at org.apache.catalina.startup.Catalina.process(Catalina.java:180) ... 5 more ============================================== ============================================== When I have NO log4j-1.2.6.jar (anywhere in the catalina heirarchy), The tomcat system will startup, but when I execute the Realm (via a request), i get this: java.lang.ExceptionInInitializerError at com.iverticalleap.security.module.tomcat.Realm.authenticate(Realm.java:1 51) at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAut henticator.java:263) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(Authenticator Base.java:458) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.i nvokeNext(StandardPipeline.java:641) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:4 80) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:239 6) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java :180) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.i nvokeNext(StandardPipeline.java:643) at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherVa lve.java:170) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.i nvokeNext(StandardPipeline.java:641) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java :172) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.i nvokeNext(StandardPipeline.java:641) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:4 80) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve. java:174) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.i nvokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:4 80) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:223) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:40 5) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processC onnection(Http11Protocol.java:380) at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:50 8) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool .java:533) at java.lang.Thread.run(Thread.java:536) Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: o rg.apache.commons.logging.LogConfigurationException: Class org.apache.commons.logging.impl.Jdk14Logger does not implemen t Log at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImp l.java:555) at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImp l.java:289) at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImp l.java:259) at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:390) at com.iverticalleap.util.logging.AbstractLoggable.getLog(AbstractLoggable. java:28) at com.iverticalleap.util.logging.AbstractLoggable.logDebug(AbstractLoggabl e.java:189) at com.iverticalleap.util.pool.AbstractBroker.<init>(AbstractBroker.java:39 ) at com.iverticalleap.util.pool.AbstractBroker.<init>(AbstractBroker.java:44 ) at com.iverticalleap.service.ServiceBroker.<init>(ServiceBroker.java:27) at com.iverticalleap.service.ServiceBroker.<clinit>(ServiceBroker.java:23) ... 25 more Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: C lass org.apache.commons.logging.impl.Jdk14Logger does not implement Log at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFact oryImpl.java:420) at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImp l.java:548) ... 34 more Caused by: org.apache.commons.logging.LogConfigurationException: Class org.apache.commons.logging.impl.Jdk14Logger does not implement Log at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFact oryImpl.java:416) ... 35 more With log4j in the server/lib dir, I get a similar message stating "Log4JCategoryLog does not implement Log" ============================================== In conclusion, I've spent a great deal of time looking into this, and I believe it may be a manifestation of a combination of problems. I may be able to help figure this out if the following questions can be answered: >From the commons-logging developers: ---- Why is the class loading done this way? Is it necessary? Why are both the JDK14 and log4j loggers failing to test as assignableFrom(Log) in the catalina server-side (not webapp-side) runtime environment? >From the catalina developers: ---- Why can a server component (Realm) find a class from a webapp's lib directory via the Thread.currentThread().getContextClassLoader().loadClass() without a ClassNotFoundException? I'm not even sure this is possible, but if catalina allows a class to be loaded or even instantiated via a particular classloader (thread context), but the typical classloader is used to determine MyClassThatImplementsLogFromThreadContextClassLoader.assignableFrom(Log. class), this would explain why nothing passes the implementation test in the LogFactory.class. Last conclusion, am I crazy? ;) Any thoughts are welcome and we come to a solution, I'll be glad to submit a patch. -Kevin Ross -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>