Re: commons-logging classloading (continued)
On 19 Nov 2003, at 18:25, Richard Sitze wrote: Regarding a pluggable LogFactory. It's already there. Unfortunately, it's behaviour isn't ideal... Log4J seems to have taken a pre-emenant place in the scheme of things. [That's been discussed before, forgive me for not digging up the details at this point.] i'm not sure whether i understand you correctly. there's only LogFactory implementation available in the commons-logging cvs repository. i'd like to see some alternatives (one possible based on discovery) in something like contrib or optional. this would allow people to use the system property to easily and completely replace the default LogFactory implementation. - robert - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
RE: commons-logging classloading (continued)
So, I'm coming into this a bit late and all, and I know a few others have been looking at this over the past few weeks... hope this does more than just add fuel to the fire. commons-discovery was created to address the classloader usage patterns being discussed : how to discover an implemention for a given interface. Commons-discovery was explicitly designed to be a general replacement for LogFactory - I'd like to see LogFactory eliminated entirely from commons-logging. On the surface, you may not find that commons-discovery does anything more than LogFactory. Underneath, it's a set of tools that let you setup your own patterns. That said: LogFactory was designed to work in a J2EE environment by dropping it into the Server level. It also functions quite well embedded into the application. As is being discovered, it doesn't work so well if you want some hybrid of that. It's a known problem, and I'm sorry to say I simply don't see ANY straight forward fix available - particularly by working with the ClassLoaders. The following was proposed: if (!Log.class.isAssignableFrom(logClass)) { // Plan B. Bend over backwards to continue Class logInterface = LoadClass(org.apache.commons.logging.Log); if (logInterface == null) { throw new LogConfigurationException (Log interface can not be found); } if (!logInterface.isAssignableFrom(logClass)) throw new LogConfigurationException (Class + logClassName + does not implement Log); } The situation: - logClass bundled into a webapp. - commons-logging bundled into a webapp, with local configuration settings. - commons-logging bundled into the webserver, with global configuration settings. Clearly logClass, which implemented the local copy of Log, failed to load because it doesn't implement the (expected) global copy of Log. Calling LoadClass(org.apache.commons.logging.Log) will only return the global copy - classloaders (by design) always defer to parent classloaders. In this case, the web-app classloader gives the server classloader first crack at loading Log. You simply don't have anyway to see the local copy that's the fundamental problem. *** Richard A. Sitze IBM WebSphere WebServices Development It's a kind of growing pain with the success of Commons. Some servers have some commons jars while others not. In the application you always include jars you needed. At the end of day, situation like that seems inevitable, not just logging, not mention the version problem. Is it possible some standard be set or a classloader component in Commons? - sean --- Ojares Rami EINT [EMAIL PROTECTED] wrote: Well put Norbert. I think that since classloading and threads are such complex issues there should be a way to not use the pattern of loading the implementation from thread's context classloader. (Hint to Craig :) - rami -Original Message- From: Norbert Klose [mailto:[EMAIL PROTECTED] Sent: Thursday, October 30, 2003 12:21 PM To: [EMAIL PROTECTED] Subject: commons-logging classloading (continued) Hello, i currently use Tomcat 4.1.27 bundled with commons-logging 1.0.3. My own webapp i'm working on also uses commons-logging, so i include a copy of the jar file into the WEB-INF/lib directory to be protable to other servlet containers that does not include the commons-logging package. I found some discussions in the mail archive that is about commons-logging and its class loading strategy. But as i could not found an anwser to my problem, i post my problem here again, hoping to get a hint for a solution (or maybe to settle on a new consens). The problem is, that when tomcat wants to anser a HTTPS request it instantiates a Http11ConnectionHandler which processes the connection. The Http11ConnectionHandler instance itself instantiates a JSSE14Support class which itself instantiates a org.apache.commons.logging.Log implementation class. Because the thread that runs the Http11ConnectionHandler has the WebappClassloader of my web application as its context class loader (which ist used by commons-logging to load the Log implementation (logClass)), BUT the org.apache.commons.logging.Log interface itself was loaded from the Common StandardClassLoader, the predicate in LogFactoryImpl.getLogConstructor() (!Log.class.isAssignableFrom(logClass)) is false, so that LogFactoryImpl.getLogConstructor() throws a LogConfigurationException. Because both classes are loaded from different classloaders. IMHO what commons-logging MUST ensure to work correctly is, that the logClass is loaded from the same classloader than the Log.class is and this is not guaranteed by the current implementation! For example protected static ClassLoader getContextClassLoader() throws
Re: commons-logging classloading (continued)
Forgive me for jumping in with a comment, I have the interest if not the experience (at least not of the rest of this thread.) I'm wondering ... is the issue loading the local webapp's version of commons logging, or getting to it's configuration? Assuming a robust/stable interface/implementation of CL, I have to assume the latter. Having a copy of CL bundled with the webapp ought be just a fallback. So, does that change the problem from class loading to resource loading? Is it possible to get to the webapp's resource, [whereas getting to the webapps classes might lead to a Link error.] I don't know the details of resource loading, but I wonder if it is less of a rats nest than class loading. I wonder if one could as for local-commonslogging.properties and if not found go for commonslogging.properties [shipped with CL or whatever.] Unlike classloading, I assume one can have multiple resources in memory more easily. That said, I don't know if one can teach the log load to detect that a webapp was just loaded (if the Log class is already in memory). I assume this is doable though. Just a random thought... regards Adam - Original Message - From: Richard Sitze [EMAIL PROTECTED] To: Jakarta Commons Developers List [EMAIL PROTECTED] Sent: Tuesday, November 18, 2003 12:51 PM Subject: RE: commons-logging classloading (continued) So, I'm coming into this a bit late and all, and I know a few others have been looking at this over the past few weeks... hope this does more than just add fuel to the fire. commons-discovery was created to address the classloader usage patterns being discussed : how to discover an implemention for a given interface. Commons-discovery was explicitly designed to be a general replacement for LogFactory - I'd like to see LogFactory eliminated entirely from commons-logging. On the surface, you may not find that commons-discovery does anything more than LogFactory. Underneath, it's a set of tools that let you setup your own patterns. That said: LogFactory was designed to work in a J2EE environment by dropping it into the Server level. It also functions quite well embedded into the application. As is being discovered, it doesn't work so well if you want some hybrid of that. It's a known problem, and I'm sorry to say I simply don't see ANY straight forward fix available - particularly by working with the ClassLoaders. The following was proposed: if (!Log.class.isAssignableFrom(logClass)) { // Plan B. Bend over backwards to continue Class logInterface = LoadClass(org.apache.commons.logging.Log); if (logInterface == null) { throw new LogConfigurationException (Log interface can not be found); } if (!logInterface.isAssignableFrom(logClass)) throw new LogConfigurationException (Class + logClassName + does not implement Log); } The situation: - logClass bundled into a webapp. - commons-logging bundled into a webapp, with local configuration settings. - commons-logging bundled into the webserver, with global configuration settings. Clearly logClass, which implemented the local copy of Log, failed to load because it doesn't implement the (expected) global copy of Log. Calling LoadClass(org.apache.commons.logging.Log) will only return the global copy - classloaders (by design) always defer to parent classloaders. In this case, the web-app classloader gives the server classloader first crack at loading Log. You simply don't have anyway to see the local copy that's the fundamental problem. *** Richard A. Sitze IBM WebSphere WebServices Development It's a kind of growing pain with the success of Commons. Some servers have some commons jars while others not. In the application you always include jars you needed. At the end of day, situation like that seems inevitable, not just logging, not mention the version problem. Is it possible some standard be set or a classloader component in Commons? - sean --- Ojares Rami EINT [EMAIL PROTECTED] wrote: Well put Norbert. I think that since classloading and threads are such complex issues there should be a way to not use the pattern of loading the implementation from thread's context classloader. (Hint to Craig :) - rami -Original Message- From: Norbert Klose [mailto:[EMAIL PROTECTED] Sent: Thursday, October 30, 2003 12:21 PM To: [EMAIL PROTECTED] Subject: commons-logging classloading (continued) Hello, i currently use Tomcat 4.1.27 bundled with commons-logging 1.0.3. My own webapp i'm working on also uses commons-logging, so i include a copy of the jar file into the WEB-INF/lib directory to be protable to other servlet containers that does not include the commons-logging package. I found some discussions in the mail archive that is about
Re: commons-logging classloading (continued)
hi richard On 18 Nov 2003, at 19:51, Richard Sitze wrote: So, I'm coming into this a bit late and all, and I know a few others have been looking at this over the past few weeks... hope this does more than just add fuel to the fire. commons-discovery was created to address the classloader usage patterns being discussed : how to discover an implemention for a given interface. Commons-discovery was explicitly designed to be a general replacement for LogFactory - I'd like to see LogFactory eliminated entirely from commons-logging. i don't think that there's any chance of that. (i also suspect that there's very little chance of adding a core dependency upon a discovery replacement.) On the surface, you may not find that commons-discovery does anything more than LogFactory. Underneath, it's a set of tools that let you setup your own patterns. i think that the problems reported with classloaders mostly fall into a few distinct categories. some are due to misguided administration policies (and we can do very little about that). some are down to the conflict between the behaviour required for correct function when logging in modern servlet containers and different classloader environments. other are down to the need for hybrid uses (to borrow your phrase from later in the email - i have the advantage of being able to read it all before replying :) we can do very little about misguided administration policies but there are things we can do about the others. i think that offer different LogFactory implementations are part of the solution. a user operating in an unusual environment would then be able to choose to run another implementation by adding the appropriate -D switch on the command line. i'd support an optional discovery based LogFactory implementation (but not a core one). even if users didn't use it directly, it would give them a positive example they could based more sophisticated discovery-based solutions on. fancy giving this a go? That said: LogFactory was designed to work in a J2EE environment by dropping it into the Server level. It also functions quite well embedded into the application. As is being discovered, it doesn't work so well if you want some hybrid of that. It's a known problem, and I'm sorry to say I simply don't see ANY straight forward fix available - particularly by working with the ClassLoaders. The following was proposed: if (!Log.class.isAssignableFrom(logClass)) { // Plan B. Bend over backwards to continue Class logInterface = LoadClass(org.apache.commons.logging.Log); if (logInterface == null) { throw new LogConfigurationException (Log interface can not be found); } if (!logInterface.isAssignableFrom(logClass)) throw new LogConfigurationException (Class + logClassName + does not implement Log); } The situation: - logClass bundled into a webapp. - commons-logging bundled into a webapp, with local configuration settings. - commons-logging bundled into the webserver, with global configuration settings. Clearly logClass, which implemented the local copy of Log, failed to load because it doesn't implement the (expected) global copy of Log. Calling LoadClass(org.apache.commons.logging.Log) will only return the global copy - classloaders (by design) always defer to parent classloaders. In this case, the web-app classloader gives the server classloader first crack at loading Log. You simply don't have anyway to see the local copy that's the fundamental problem. i'm not sure that it is in this case. i have a feeling that some of the reports came from containers which used other (older?) classloading strategies. that's why some people have reported some success when loading from the LogFactory.getClassloader.loadClass(). i agree that it's not a proper solution but it'd probably make life a little easier for people using containers with odd (or older) classloading strategies. BTW one of my person bugbears is that commons-logging throws exceptions when logging configuration fails. there is no technical reason why we could not give the user an system property that suppresses all exceptions and uses a very simple default logger. comments anyone? - robert - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: commons-logging classloading (continued)
Will Jaynes wrote: robert burrell donkin wrote: ... 2, a more sophisticated implementation for the loading of the LogFactory implementation that would try to load the class from the LogFactory class classloader if the assignment fails. since (at the moment) we throw an exception in this circumstance (from would be very difficult to recover from), i don't think that add this extra step would do any harm. comments anyone? I agree with Norbert that the central remaining classloading problem is that the Log interface may not have been loaded by the same classloader as the log implementation, so the isAssignableFrom test fails. To be consistent, the Log interface should be loaded by the loadClass() method, just as the logClass is. Here's my suggested code change from LogFactoryImpl.getLogConstructor(): // Attempt to load the Log implementation class Class logClass = null; Class logInterface = null; try { logClass = loadClass(logClassName); logInterface = loadClass(org.apache.commons.logging.Log); if (logClass == null) { throw new LogConfigurationException (No suitable Log implementation for + logClassName); } if (logInterface == null) { throw new LogConfigurationException (Log interface not found by classloader); } if (!logInterface.isAssignableFrom(logClass)) { throw new LogConfigurationException (Class + logClassName + does not implement Log); } } catch (Throwable t) { throw new LogConfigurationException(t); } It is certainly possible to also add Robert's suggestion of trying the LogFactory class classloader if the initial load fails, but I don't think that is necessary. Will Well, I submitted this as a bug and included a patch. But Remy immediately marked it as RESOLVED/WONTFIX. He doesn't really address my suggestion other than to say that c-l if used properly ... is well thought out, and works perfectly well I would never suggest that c-l is not well thought out. However, I don't think that all the problems we see involving c-l classloading can be attributed to us not using c-l properly. It may work perfectly well with Tomcat5, but that doesn't mean there aren't improvements that can be made. Or even accomodations that could be made to other containers than Tomcat5. Could someone please explain why the suggestion to load the Log interface with the loadClass() method is not acceptable. Will - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: commons-logging classloading (continued)
Will Jaynes wrote: Well, I submitted this as a bug and included a patch. But Remy immediately marked it as RESOLVED/WONTFIX. He doesn't really address my suggestion other than to say that c-l if used properly ... is well thought out, and works perfectly well I would never suggest that c-l is not well thought out. However, I don't think that all the problems we see involving c-l classloading can be attributed to us not using c-l properly. It may work perfectly well with Tomcat5, but that doesn't mean there aren't improvements that can be made. Or even accomodations that could be made to other containers than Tomcat5. Could someone please explain why the suggestion to load the Log interface with the loadClass() method is not acceptable. - The core Log classes should be loaded once from one place (= (basically) they should be in the system classloader) - the log implementations (ex: the log4j implementation) should reside in the same classloader as the logger; ideally, the logger ships with wrapper classes for commons-logging This is the most efficient design, and fairly easy to understand. Coincidentally, this is the design that commons-logging implements, and it is good for a complex container environment. Remy - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
RE: commons-logging classloading (continued)
Well put Norbert. I think that since classloading and threads are such complex issues there should be a way to not use the pattern of loading the implementation from thread's context classloader. (Hint to Craig :) - rami -Original Message- From: Norbert Klose [mailto:[EMAIL PROTECTED] Sent: Thursday, October 30, 2003 12:21 PM To: [EMAIL PROTECTED] Subject: commons-logging classloading (continued) Hello, i currently use Tomcat 4.1.27 bundled with commons-logging 1.0.3. My own webapp i'm working on also uses commons-logging, so i include a copy of the jar file into the WEB-INF/lib directory to be protable to other servlet containers that does not include the commons-logging package. I found some discussions in the mail archive that is about commons-logging and its class loading strategy. But as i could not found an anwser to my problem, i post my problem here again, hoping to get a hint for a solution (or maybe to settle on a new consens). The problem is, that when tomcat wants to anser a HTTPS request it instantiates a Http11ConnectionHandler which processes the connection. The Http11ConnectionHandler instance itself instantiates a JSSE14Support class which itself instantiates a org.apache.commons.logging.Log implementation class. Because the thread that runs the Http11ConnectionHandler has the WebappClassloader of my web application as its context class loader (which ist used by commons-logging to load the Log implementation (logClass)), BUT the org.apache.commons.logging.Log interface itself was loaded from the Common StandardClassLoader, the predicate in LogFactoryImpl.getLogConstructor() (!Log.class.isAssignableFrom(logClass)) is false, so that LogFactoryImpl.getLogConstructor() throws a LogConfigurationException. Because both classes are loaded from different classloaders. IMHO what commons-logging MUST ensure to work correctly is, that the logClass is loaded from the same classloader than the Log.class is and this is not guaranteed by the current implementation! For example protected static ClassLoader getContextClassLoader() throws LogConfigurationException { return Log.class.getClassLoader(); } would do. BUT to keep the current implementation what about changing LogFactoryImpl.getLogConstructor(), so that the correct predicate is evaluated? protected Constructor getLogConstructor() throws LogConfigurationException { ... logClass = loadClass(logClassName); ___logClass___ = loadClass(org.apache.commons.logging.Log)// something like this... if (logClass == null) { throw new LogConfigurationException (No suitable Log implementation for + logClassName); } if (!___logClass___.class.isAssignableFrom(logClass)) { ... } ... } The problem with the current implementation is, that commons-logging can not rely on the fact that the threads current context class loader is the classloader that the class (like the JSSE14Support above) wants to get its logging implementation from!!! Is there a chance to get a consens on that, or at least to think about changing the current implemetation making it more reliable ? Kindly regards, Norbert. -- __ Sign-up for your own personalized E-mail at Mail.com http://www.mail.com/?sr=signup CareerBuilder.com has over 400,000 jobs. Be smarter about your job search http://corp.mail.com/careers - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
RE: commons-logging classloading (continued)
It's a kind of growing pain with the success of Commons. Some servers have some commons jars while others not. In the application you always include jars you needed. At the end of day, situation like that seems inevitable, not just logging, not mention the version problem. Is it possible some standard be set or a classloader component in Commons? - sean --- Ojares Rami EINT [EMAIL PROTECTED] wrote: Well put Norbert. I think that since classloading and threads are such complex issues there should be a way to not use the pattern of loading the implementation from thread's context classloader. (Hint to Craig :) - rami -Original Message- From: Norbert Klose [mailto:[EMAIL PROTECTED] Sent: Thursday, October 30, 2003 12:21 PM To: [EMAIL PROTECTED] Subject: commons-logging classloading (continued) Hello, i currently use Tomcat 4.1.27 bundled with commons-logging 1.0.3. My own webapp i'm working on also uses commons-logging, so i include a copy of the jar file into the WEB-INF/lib directory to be protable to other servlet containers that does not include the commons-logging package. I found some discussions in the mail archive that is about commons-logging and its class loading strategy. But as i could not found an anwser to my problem, i post my problem here again, hoping to get a hint for a solution (or maybe to settle on a new consens). The problem is, that when tomcat wants to anser a HTTPS request it instantiates a Http11ConnectionHandler which processes the connection. The Http11ConnectionHandler instance itself instantiates a JSSE14Support class which itself instantiates a org.apache.commons.logging.Log implementation class. Because the thread that runs the Http11ConnectionHandler has the WebappClassloader of my web application as its context class loader (which ist used by commons-logging to load the Log implementation (logClass)), BUT the org.apache.commons.logging.Log interface itself was loaded from the Common StandardClassLoader, the predicate in LogFactoryImpl.getLogConstructor() (!Log.class.isAssignableFrom(logClass)) is false, so that LogFactoryImpl.getLogConstructor() throws a LogConfigurationException. Because both classes are loaded from different classloaders. IMHO what commons-logging MUST ensure to work correctly is, that the logClass is loaded from the same classloader than the Log.class is and this is not guaranteed by the current implementation! For example protected static ClassLoader getContextClassLoader() throws LogConfigurationException { return Log.class.getClassLoader(); } would do. BUT to keep the current implementation what about changing LogFactoryImpl.getLogConstructor(), so that the correct predicate is evaluated? protected Constructor getLogConstructor() throws LogConfigurationException { ... logClass = loadClass(logClassName); ___logClass___ = loadClass(org.apache.commons.logging.Log) // something like this... if (logClass == null) { throw new LogConfigurationException (No suitable Log implementation for + logClassName); } if (!___logClass___.class.isAssignableFrom(logClass)) { ... } ... } The problem with the current implementation is, that commons-logging can not rely on the fact that the threads current context class loader is the classloader that the class (like the JSSE14Support above) wants to get its logging implementation from!!! Is there a chance to get a consens on that, or at least to think about changing the current implemetation making it more reliable ? Kindly regards, Norbert. -- __ Sign-up for your own personalized E-mail at Mail.com http://www.mail.com/?sr=signup CareerBuilder.com has over 400,000 jobs. Be smarter about your job search http://corp.mail.com/careers - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] __ Do you Yahoo!? Exclusive Video Premiere - Britney Spears http://launch.yahoo.com/promos/britneyspears/ - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]