Commons Logging
  1. Commons Logging
  2. LOGGING-73

[logging] TCCL problem in J2EE Container

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.0.4
    • Fix Version/s: 1.1.0
    • Labels:
      None
    • Environment:

      Operating System: other
      Platform: Other

      Description

      Everybody that uses commons-logging in an J2EE Container (especially jboss) has
      problems when the TCCL is not the same as the current ClassLoader. The solution
      cannot be to drop the commons-logging.jar out of the ear/war file, as it would
      prevent to have an application specific logging instance.

      Commons-logging preferes the TCCL which is OK. But if it finds a Logger in the
      TCCL that does not fit to the current Log interface it throws an error instead
      of trying the current CL.

      I propose to change this. I will attach a changed LogFactoryImpl.java. The
      changed factory still prefers TCCL, but will try the current class loader if the
      LOG_INTERFACE is not assignable for the class found via TCCL.

      It allows us to run more painlessly in an J2EE Container and to keep
      commons-logging class loader preferences.

        Activity

        Hide
        Dennis Lundberg added a comment -

        According to Simon this was fixed in 1.1.0.

        Show
        Dennis Lundberg added a comment - According to Simon this was fixed in 1.1.0.
        Hide
        Simon Kitching added a comment -

        The API is compatible with 1.0.x for "normal" uses of JCL.

        There are some minor incompatibilites for code that extends commons-logging
        classes; this is a pretty rare thing to do, however.

        See the release notes for full details.

        Show
        Simon Kitching added a comment - The API is compatible with 1.0.x for "normal" uses of JCL. There are some minor incompatibilites for code that extends commons-logging classes; this is a pretty rare thing to do, however. See the release notes for full details.
        Hide
        Michael Kopp added a comment -

        Are the interfaces compatible with the 1.0X version? As you might remember we
        are not using commons-logging directly but through thirdparty. And of course we
        cannot change that code...

        Show
        Michael Kopp added a comment - Are the interfaces compatible with the 1.0X version? As you might remember we are not using commons-logging directly but through thirdparty. And of course we cannot change that code...
        Hide
        rdonkin@apache.org added a comment -

        Please retest with latest release candidate. This can be found in
        http://people.apache.org/~rdonkin/commons-logging.

        Use of the TCCL is now flaggable but I suspect that logging may function (though
        the per application configuration may not be too great) so please test both.

        Show
        rdonkin@apache.org added a comment - Please retest with latest release candidate. This can be found in http://people.apache.org/~rdonkin/commons-logging . Use of the TCCL is now flaggable but I suspect that logging may function (though the per application configuration may not be too great) so please test both.
        Hide
        Dimitry E Voytenko added a comment -

        i moved this proposal into the separate issue (36927).

        Show
        Dimitry E Voytenko added a comment - i moved this proposal into the separate issue (36927).
        Hide
        Dimitry E Voytenko added a comment -

        Hi,

        Somewhat related problem with using TCL in the shared environment (Tomcat). For
        instance I have application A (classloader A) and class A1 that invokes class
        S1 in the shared classloader S. Class S1 has static initializer for logger
        (static Log log = LogFactory.getLog(...)). Provided A1 will be the first one to
        access S1, JCL's LogFactory will use instance cached with A classloader and
        will be (possibly) creating logs within the same A classloader. Further if A is
        undeployed, there will be no way to notify S that it's Log instance is not up-
        to-date anymore. This would lead to the memory leaks, even if ClassLoader is
        removed from LogFactory's cache. In addition, such situation will be illogical -
        why should child's classloader used for initialization of parent's classloader?

        A propose a solution that is a compromize b/w server/client idea and static
        linking would be to have a setting (in the system properties) that would
        instruct JCL to not use TCCL (e.g. org.apache.logging.DISABLE_TCCL). In this
        mode, inspection and cache would be performed in the classloader of the
        LogFactory. This solution will work good for both: shared environments (Tomcat
        or JBoss with UCL) and for deployments with JCL in the WEB-INF/lib.

        Show
        Dimitry E Voytenko added a comment - Hi, Somewhat related problem with using TCL in the shared environment (Tomcat). For instance I have application A (classloader A) and class A1 that invokes class S1 in the shared classloader S. Class S1 has static initializer for logger (static Log log = LogFactory.getLog(...)). Provided A1 will be the first one to access S1, JCL's LogFactory will use instance cached with A classloader and will be (possibly) creating logs within the same A classloader. Further if A is undeployed, there will be no way to notify S that it's Log instance is not up- to-date anymore. This would lead to the memory leaks, even if ClassLoader is removed from LogFactory's cache. In addition, such situation will be illogical - why should child's classloader used for initialization of parent's classloader? A propose a solution that is a compromize b/w server/client idea and static linking would be to have a setting (in the system properties) that would instruct JCL to not use TCCL (e.g. org.apache.logging.DISABLE_TCCL). In this mode, inspection and cache would be performed in the classloader of the LogFactory. This solution will work good for both: shared environments (Tomcat or JBoss with UCL) and for deployments with JCL in the WEB-INF/lib.
        Hide
        Michael Kopp added a comment -

        1. The J2EE Spec does not specify which classloader the TCCL should contains.
        only that it should be there.
        2. Most AppServers won't have JCL in the common-classloader, jboss is the
        exception I would say. The common classloader there contains way to much.

        jboss seems to ignore the TCCL most of the time.
        It all comes down to the fact that we cannot know what the TCCL contains at a
        given time. Because it is not defined!
        I had this problem now in:

        • jmx-console calling mbean with Web TCCL
        • jmx-console calling mbean calling ejb with Web TCCL in the ejbCreate call!!!
        • instantiation of ManagedConnectionFactory/ManagedConnection (JCA) by jboss JCA
          Pool Loader with jboss TCCL

        Of course this is all in jboss, but as it is defined nowhere (at least I
        couldn't find it) I consider TCCL not reliable!!

        And many more. I changed the 1.0.4 commons-logging the way it is described in my
        patch and replaced it in jboss and all other apps. Now it works as expected.

        Show
        Michael Kopp added a comment - 1. The J2EE Spec does not specify which classloader the TCCL should contains. only that it should be there. 2. Most AppServers won't have JCL in the common-classloader, jboss is the exception I would say. The common classloader there contains way to much. jboss seems to ignore the TCCL most of the time. It all comes down to the fact that we cannot know what the TCCL contains at a given time. Because it is not defined! I had this problem now in: jmx-console calling mbean with Web TCCL jmx-console calling mbean calling ejb with Web TCCL in the ejbCreate call!!! instantiation of ManagedConnectionFactory/ManagedConnection (JCA) by jboss JCA Pool Loader with jboss TCCL Of course this is all in jboss, but as it is defined nowhere (at least I couldn't find it) I consider TCCL not reliable!! And many more. I changed the 1.0.4 commons-logging the way it is described in my patch and replaced it in jboss and all other apps. Now it works as expected.
        Hide
        Brian Stansberry added a comment -

        I haven't had a chance to fully digest this thread, so please forgive me if I'm
        way off base.

        In the specific scenario Michael described, JCL is available in a classloader
        that is a common parent of both apps involved in the "Inter-App" call. If the
        webapp deployed commons-logging-adapters.jar instead of the full
        commons-logging.jar there should be no Log incompatibility problems nor any
        memory leak. The logging would end up going to the loggers associated with the
        TCCL, which may or may not be the desired behavior. But that seems more like a
        problem with ensuring the TCCL is properly set when a thread crosses an app
        boundary and not something JCL can fix. (e.g. it seems to me that if a thread
        spawned by a timer service calls into an MBean, the TCCL should be set to the
        MBean's classloader before the call is made).

        What I'm suggesting of course wouldn't work if JCL wasn't available in a shared
        classloader, so I don't mean to imply some of the ideas raised on this thread
        are unneeded. But a commons-logging-adapters.jar approach might be a good
        workaround for the issue Michael specifically raised. (Such a jar doesn't exist
        in JCL 1.0.4, the latest official release, but it's simple enough to create one
        by taking commons-logging.jar and removing all classes found in
        commons-logging-api.jar).

        Show
        Brian Stansberry added a comment - I haven't had a chance to fully digest this thread, so please forgive me if I'm way off base. In the specific scenario Michael described, JCL is available in a classloader that is a common parent of both apps involved in the "Inter-App" call. If the webapp deployed commons-logging-adapters.jar instead of the full commons-logging.jar there should be no Log incompatibility problems nor any memory leak. The logging would end up going to the loggers associated with the TCCL, which may or may not be the desired behavior. But that seems more like a problem with ensuring the TCCL is properly set when a thread crosses an app boundary and not something JCL can fix. (e.g. it seems to me that if a thread spawned by a timer service calls into an MBean, the TCCL should be set to the MBean's classloader before the call is made). What I'm suggesting of course wouldn't work if JCL wasn't available in a shared classloader, so I don't mean to imply some of the ideas raised on this thread are unneeded. But a commons-logging-adapters.jar approach might be a good workaround for the issue Michael specifically raised. (Such a jar doesn't exist in JCL 1.0.4, the latest official release, but it's simple enough to create one by taking commons-logging.jar and removing all classes found in commons-logging-api.jar).
        Hide
        rdonkin@apache.org added a comment -

        I won't have time today to code anything up right now but I have been thinking and playing around with
        various exotic cases (such as the JCA). I suspect that the problems in these cases arise when (as in this
        case) code has been loaded is a sibling (or cousin) load to the application code. In this case, TCCL either
        cannot load the implementation classes or when it can load them but they are defined by an incompatible
        loader.

        I think that it should be possible to diagnose this case by checking the Log class loaded by TCCL. If it
        cannot be loaded or is not compatible with the Log class loaded by the class classloader, then TCCL
        should not be used by JCL.

        Show
        rdonkin@apache.org added a comment - I won't have time today to code anything up right now but I have been thinking and playing around with various exotic cases (such as the JCA). I suspect that the problems in these cases arise when (as in this case) code has been loaded is a sibling (or cousin) load to the application code. In this case, TCCL either cannot load the implementation classes or when it can load them but they are defined by an incompatible loader. I think that it should be possible to diagnose this case by checking the Log class loaded by TCCL. If it cannot be loaded or is not compatible with the Log class loaded by the class classloader, then TCCL should not be used by JCL.
        Hide
        Simon Kitching added a comment -

        Yes, the DON_QUIXOTE experimental branch of JCL did come to mind while I was
        writing that. As we're committed to a non-compatible 1.1 release it might be
        time to revisit that.

        The problem with going to a fully refactored release as we've looked at in some
        of the more radical restructures is of course that it will take many months to
        get that done at our current rate. Still, there's no point in putting out a new
        release that doesn't properly fix the known problems.

        BTW, if anyone out there wishes to hire me to work on this full-time to get a
        new release out sooner, I'm available

        Show
        Simon Kitching added a comment - Yes, the DON_QUIXOTE experimental branch of JCL did come to mind while I was writing that. As we're committed to a non-compatible 1.1 release it might be time to revisit that. The problem with going to a fully refactored release as we've looked at in some of the more radical restructures is of course that it will take many months to get that done at our current rate. Still, there's no point in putting out a new release that doesn't properly fix the known problems. BTW, if anyone out there wishes to hire me to work on this full-time to get a new release out sooner, I'm available
        Hide
        rdonkin@apache.org added a comment -

        I think I've managed to get my head around this one...

        Simon's analysis seems good but I'd like to add a few random comments...

        Exotic ClassLoaders
        -----------------
        When used in a JCA, this is a use case where JCL really can't gather enough information to configure
        itself correctly. It's tough. It's good to have a solid use case for exotic classloading. I think when I was
        thinking about exotic classloaders, I thought that there was something that could be done for cases
        such as this: along the lines of recognizing that TCCL is busted and default to use the class classloader.

        Good point from Simon (though) that busted TCCL's should be not cached. Would need to think about
        performance but maybe bad performance is better than total refusal to run...

        Static Binding
        -----------
        If I've understood this correctly, the client and server jars would use static binding to determine the
        LogFactoryImpl to be use. There's a certain amount of convergence here: DON_QUIXOTE and SLF4J. I'd
        prefer to implement a long term solution (prune back to a minimal set of statically bound classes and
        interfaces) rather than a short term fix (client and server jars). I'm not so religous as Simon about jar
        proliferation but he's right that more jars need more explaination and so more quality documentation.

        I've been wanting for a while to look at using byte code engineering to statically bind different discovery
        strategies. Michael Kopp's is an advanced use case. If he's using a child-first classloader then
        (hyopthetically) he could just run the enhancer over all the jars and rewire the discovery. Maybe one day
        I'll find the time to get this working...

        Show
        rdonkin@apache.org added a comment - I think I've managed to get my head around this one... Simon's analysis seems good but I'd like to add a few random comments... Exotic ClassLoaders ----------------- When used in a JCA, this is a use case where JCL really can't gather enough information to configure itself correctly. It's tough. It's good to have a solid use case for exotic classloading. I think when I was thinking about exotic classloaders, I thought that there was something that could be done for cases such as this: along the lines of recognizing that TCCL is busted and default to use the class classloader. Good point from Simon (though) that busted TCCL's should be not cached. Would need to think about performance but maybe bad performance is better than total refusal to run... Static Binding ----------- If I've understood this correctly, the client and server jars would use static binding to determine the LogFactoryImpl to be use. There's a certain amount of convergence here: DON_QUIXOTE and SLF4J. I'd prefer to implement a long term solution (prune back to a minimal set of statically bound classes and interfaces) rather than a short term fix (client and server jars). I'm not so religous as Simon about jar proliferation but he's right that more jars need more explaination and so more quality documentation. I've been wanting for a while to look at using byte code engineering to statically bind different discovery strategies. Michael Kopp's is an advanced use case. If he's using a child-first classloader then (hyopthetically) he could just run the enhancer over all the jars and rewire the discovery. Maybe one day I'll find the time to get this working...
        Hide
        Michael Kopp added a comment -

        Well the point of opensource is to have a community in order to improve the
        quality right? So the users should not only complain, but help to make it better.

        So I'm glad to be of help to the project. In the end I'm helping myself.

        Show
        Michael Kopp added a comment - Well the point of opensource is to have a community in order to improve the quality right? So the users should not only complain, but help to make it better. So I'm glad to be of help to the project. In the end I'm helping myself.
        Hide
        Simon Kitching added a comment -

        I agree it is necessary to address this scenario. Thanks very much for your
        explanation of the issues. One of the problems with commons-logging is that
        there is very little information on the situations it has to handle. Slowly this
        information is being built up, and the information you have provided here is
        very useful indeed.

        Show
        Simon Kitching added a comment - I agree it is necessary to address this scenario. Thanks very much for your explanation of the issues. One of the problems with commons-logging is that there is very little information on the situations it has to handle. Slowly this information is being built up, and the information you have provided here is very useful indeed.
        Hide
        Michael Kopp added a comment -

        I agree that is a huge change. But I think it is a also necessary one. After all
        I'm not the only one having this kind of problem. And we already invested many
        hours finding issues around that.

        So I hope you find a good solution about this. I would really appreciate it.

        Show
        Michael Kopp added a comment - I agree that is a huge change. But I think it is a also necessary one. After all I'm not the only one having this kind of problem. And we already invested many hours finding issues around that. So I hope you find a good solution about this. I would really appreciate it.
        Hide
        Simon Kitching added a comment -

        Here's the problem I mentioned earlier in more detail:

        LogFactory always keeps a map of LogFactoryImpl instances keyed by context
        classloader so that when deployed in a shared classloader each webapp gets an
        independent logging setup.

        When webapp B makes an inter-app call to C. Code in C calls LogFactory.getLog.
        tries to look up a LogFactoryImpl by TCCL in its map. There isn't one, so it
        goes into its discovery process. This is what is currently causing problems, but
        assuming we fix it somehow [as per your suggestion] a LogFactoryImpl object will
        be returned. LogFactory then caches it using the current TCCL.

        Later someone undeploys webapp B. Normally, the reference count for the TCCL for
        B will drop to zero at that point, and all the classes associated with B will be
        garbage-collected (including all the static member variables, etc). However
        because the map in the LogFactory class loaded by C has a key that references B
        this won't happen.

        Log4j's default setup works because it effectively has two modes: "server" and
        "app". The default is "app", where it doesn't care about TCCL and always uses
        the default hierarchy. However it can be configured to use a
        ContextHierarchySelector or somesuch name; when deployed via a shared classpath
        the user needs to enable this selector in order to get independent logging for
        each app. Note that if you enabled log4j's ContextHierarchySelector in
        classloader C you would get the same memory leakage problem as JCL suffers.

        JCL is effectively always in "server" mode, with the assumption that if it was
        actually deployed in a webapp's classpath then it is a server with only one
        client TCCL - the app. However the "inter-app" stuff screws this up because JCL
        deployed via a webapp ends up seeing multiple client TCCLs.

        So I guess we could provide a config option for LogFactory which tells it to act
        in server or client mode, and if in client then it avoids using the TCCL.

        This will be a nuisance for every system that deploys logging libs via a shared
        classloader (and that is a lot of them). And I don't know how we would provide
        any kind of "backward compatibility". Maybe there is some way to do reasonable
        auto-detection of client vs server mode? Like walk the classloader tree looking
        for a copy of JCL at a higher level and assume client mode if one is found? Not
        sure that's reliable enough...

        Maybe the answer is two different JCL jars: a client jar and a server jar? That
        sounds nicer. webapps bundle the client jar, and that only ever has one
        LogFactoryImpl. In this case we also know that adapters should be located via
        LogFactoryImpl's classloader so that fixes your reported problem too. The server
        jar has an implementation that uses a Map keyed by TCCL and locates adapters via
        TCCL. This is a significant change, though, with API breakage.

        Show
        Simon Kitching added a comment - Here's the problem I mentioned earlier in more detail: LogFactory always keeps a map of LogFactoryImpl instances keyed by context classloader so that when deployed in a shared classloader each webapp gets an independent logging setup. When webapp B makes an inter-app call to C. Code in C calls LogFactory.getLog. tries to look up a LogFactoryImpl by TCCL in its map. There isn't one, so it goes into its discovery process. This is what is currently causing problems, but assuming we fix it somehow [as per your suggestion] a LogFactoryImpl object will be returned. LogFactory then caches it using the current TCCL. Later someone undeploys webapp B. Normally, the reference count for the TCCL for B will drop to zero at that point, and all the classes associated with B will be garbage-collected (including all the static member variables, etc). However because the map in the LogFactory class loaded by C has a key that references B this won't happen. Log4j's default setup works because it effectively has two modes: "server" and "app". The default is "app", where it doesn't care about TCCL and always uses the default hierarchy. However it can be configured to use a ContextHierarchySelector or somesuch name; when deployed via a shared classpath the user needs to enable this selector in order to get independent logging for each app. Note that if you enabled log4j's ContextHierarchySelector in classloader C you would get the same memory leakage problem as JCL suffers. JCL is effectively always in "server" mode, with the assumption that if it was actually deployed in a webapp's classpath then it is a server with only one client TCCL - the app. However the "inter-app" stuff screws this up because JCL deployed via a webapp ends up seeing multiple client TCCLs. So I guess we could provide a config option for LogFactory which tells it to act in server or client mode, and if in client then it avoids using the TCCL. This will be a nuisance for every system that deploys logging libs via a shared classloader (and that is a lot of them). And I don't know how we would provide any kind of "backward compatibility". Maybe there is some way to do reasonable auto-detection of client vs server mode? Like walk the classloader tree looking for a copy of JCL at a higher level and assume client mode if one is found? Not sure that's reliable enough... Maybe the answer is two different JCL jars: a client jar and a server jar? That sounds nicer. webapps bundle the client jar, and that only ever has one LogFactoryImpl. In this case we also know that adapters should be located via LogFactoryImpl's classloader so that fixes your reported problem too. The server jar has an implementation that uses a Map keyed by TCCL and locates adapters via TCCL. This is a significant change, though, with API breakage.
        Hide
        Michael Kopp added a comment -

        I'm not sure about your factory map talking but consider this.

        log4j can do what I want without problems. It is rather simple, when you want to
        have your own instance, you need the jar file in your own class loader. In a
        proper j2ee environment (child first delegation), this will always lead to a new
        logger instance).

        I agree that jboss's UnifiedClassLoader is a problem in that regard. But I see
        it this way. If you want to have your own logging instance, then work without
        that damned UnifiedClassLoader.

        The thing is that these 'Inter-App' Calls are happening all the time.

        jmx-console: The TCCL is the WebClassLoader and the current is the one of the
        MBean (Application)
        jmx-scheduling: The TCCL is the one of the TimerMBean (jboss or jdk) and the
        current is the one of the MBean (Application)
        JCAPoolFiller Thread: The TCCL is the jboss-one and the current is the
        Applications ClassLoader.

        I think that my a approach can still work.
        1. Try commons-logging approach first (TCCL)
        2. If no logger is found (not assignable?) try the current class loader

        Agreed it might not always be the correct logging instance, but at least it
        would not generate an error and the log would be written.

        Show
        Michael Kopp added a comment - I'm not sure about your factory map talking but consider this. log4j can do what I want without problems. It is rather simple, when you want to have your own instance, you need the jar file in your own class loader. In a proper j2ee environment (child first delegation), this will always lead to a new logger instance). I agree that jboss's UnifiedClassLoader is a problem in that regard. But I see it this way. If you want to have your own logging instance, then work without that damned UnifiedClassLoader. The thing is that these 'Inter-App' Calls are happening all the time. jmx-console: The TCCL is the WebClassLoader and the current is the one of the MBean (Application) jmx-scheduling: The TCCL is the one of the TimerMBean (jboss or jdk) and the current is the one of the MBean (Application) JCAPoolFiller Thread: The TCCL is the jboss-one and the current is the Applications ClassLoader. I think that my a approach can still work. 1. Try commons-logging approach first (TCCL) 2. If no logger is found (not assignable?) try the current class loader Agreed it might not always be the correct logging instance, but at least it would not generate an error and the log would be written.
        Hide
        Simon Kitching added a comment -

        Yep, your description #5 matches my #4 (though yours is a bit better phrased .

        This makes things very ugly for commons-logging. The LogFactory keeps a map of
        configurations by context-classloader. So even with your proposed fix, any app
        that calls into C will cause C's LogFactory to create another LogFactoryImpl for
        that classloader. That will probably prevent the calling app's classloader from
        being garbage-collected among other nasty issues.

        Here's some initial thoughts on a full fix for this:

        Basically, if LogFactory sees that TCCL is not related to its classloader, then
        it should not retain any strong references to that TCCL, and in particular not
        use it as a key into the factories map. But if it doesn't do that, then every
        time getLog() is called and it can't find an entry in its factories map then it
        needs to walk the list of ancestors for the TCCL to see whether it is among
        them: if yes, then this is simply the "new context" scenario; if no then this is
        the "inter-app-call" scenario so it needs to ignore the TCCL and use
        LogFactory.getClassLoader as the key instead.

        Hmm. But there's another scenario in which the TCCL can be unrelated to the
        classloader for LogFactory - the jboss "UnifiedLoaderRepository" (as explained
        by Brian S.). But in that case we must use the TCCL in order to get sane
        logging configuration behaviour (remember that the whole point of trying to load
        the logging adapter classes via the TCCL is so that webapps can provide their
        own adapters, and so that logging config files in the webapp-specific classpath
        are seen).

        Currently, I don't see any way to handle this with JBoss. The combination of
        the UnifiedLoaderRepository and inter-app-calls where the TCCL is set to the
        caller appears initially unsolvable to me - not just for commons-logging, but
        for any logging system at all which can be configured on a per-app basis.

        I'll give this some more thought. All suggestions on how to resolve this are
        very welcome - though it might be more convenient to post them to commons-dev
        (with subject line starting [logging]) rather than having a discussion on these
        awkward web forms.

        Show
        Simon Kitching added a comment - Yep, your description #5 matches my #4 (though yours is a bit better phrased . This makes things very ugly for commons-logging. The LogFactory keeps a map of configurations by context-classloader. So even with your proposed fix, any app that calls into C will cause C's LogFactory to create another LogFactoryImpl for that classloader. That will probably prevent the calling app's classloader from being garbage-collected among other nasty issues. Here's some initial thoughts on a full fix for this: Basically, if LogFactory sees that TCCL is not related to its classloader, then it should not retain any strong references to that TCCL, and in particular not use it as a key into the factories map. But if it doesn't do that, then every time getLog() is called and it can't find an entry in its factories map then it needs to walk the list of ancestors for the TCCL to see whether it is among them: if yes, then this is simply the "new context" scenario; if no then this is the "inter-app-call" scenario so it needs to ignore the TCCL and use LogFactory.getClassLoader as the key instead. Hmm. But there's another scenario in which the TCCL can be unrelated to the classloader for LogFactory - the jboss "UnifiedLoaderRepository" (as explained by Brian S.). But in that case we must use the TCCL in order to get sane logging configuration behaviour (remember that the whole point of trying to load the logging adapter classes via the TCCL is so that webapps can provide their own adapters, and so that logging config files in the webapp-specific classpath are seen). Currently, I don't see any way to handle this with JBoss. The combination of the UnifiedLoaderRepository and inter-app-calls where the TCCL is set to the caller appears initially unsolvable to me - not just for commons-logging, but for any logging system at all which can be configured on a per-app basis. I'll give this some more thought. All suggestions on how to resolve this are very welcome - though it might be more convenient to post them to commons-dev (with subject line starting [logging] ) rather than having a discussion on these awkward web forms.
        Hide
        Michael Kopp added a comment -

        Small Type:

        JBoss Class Loader A (commons-logging available here)
        Application B with ClassLoader B. Child of A
        Application C with ClassLoader C. Child of A (commons-logging deployed in here)

        ClassLoader C is of course a child of A

        Show
        Michael Kopp added a comment - Small Type: JBoss Class Loader A (commons-logging available here) Application B with ClassLoader B. Child of A Application C with ClassLoader C. Child of A (commons-logging deployed in here) ClassLoader C is of course a child of A
        Hide
        Michael Kopp added a comment -

        JBoss Class Loader A (commons-logging available here)
        Application B with ClassLoader B. Child of A
        Application C with ClassLoader C. Child of C (commons-logging deployed in here)

        We have a Child First delegation as is appropriate in a J2EE Container!

        Application B initiates thread and makes a call to Application C.

        Application C contains the commons-logging in its own classloader C. We need
        this in order to have our own logging instance apart from the jboss instance.
        The Log interface used in application C is loaded by ClassLoader C as it is a
        'static' link. commons-logging will take the Log implementation from the TCCL
        which either comes from CL B or CL A. None of them will implement Log from CL C.

        This is a fairly common case in jboss. The horror is that we do not even use
        commons-logging directly, but a lot of third-party does. That and the fact that
        commons-logging is part of the jboss distribution and visiable to all
        applications, even if I have isolated class loaders.

        Show
        Michael Kopp added a comment - JBoss Class Loader A (commons-logging available here) Application B with ClassLoader B. Child of A Application C with ClassLoader C. Child of C (commons-logging deployed in here) We have a Child First delegation as is appropriate in a J2EE Container! Application B initiates thread and makes a call to Application C. Application C contains the commons-logging in its own classloader C. We need this in order to have our own logging instance apart from the jboss instance. The Log interface used in application C is loaded by ClassLoader C as it is a 'static' link. commons-logging will take the Log implementation from the TCCL which either comes from CL B or CL A. None of them will implement Log from CL C. This is a fairly common case in jboss. The horror is that we do not even use commons-logging directly, but a lot of third-party does. That and the fact that commons-logging is part of the jboss distribution and visiable to all applications, even if I have isolated class loaders.
        Hide
        Simon Kitching added a comment -

        You may have to help me out here - I'm not familiar with JCA.

        By "cross-container call" do you mean this?

        • shared classloader A defines some interface I
        • classloader B is a child of A and provides some class that implements I
        • classloader C contains some webapp. Code here invokes a lookup method
          that returns an object of type I, where the actual concrete type is A.
        • the webapp then invokes a method on I
        • the actual method on A calls commons-logging

        If not, could you please spell out exactly what classloader relationships you
        are addressing?

        Show
        Simon Kitching added a comment - You may have to help me out here - I'm not familiar with JCA. By "cross-container call" do you mean this? shared classloader A defines some interface I classloader B is a child of A and provides some class that implements I classloader C contains some webapp. Code here invokes a lookup method that returns an object of type I, where the actual concrete type is A. the webapp then invokes a method on I the actual method on A calls commons-logging If not, could you please spell out exactly what classloader relationships you are addressing?
        Hide
        Michael Kopp added a comment -

        Thanks for the fast reply.

        I checked the current trunk and unfortunatelly I do not think that the changes help.

        Consider you have a cross Container call (WebContainer to JCA Container of
        another Application).

        There is not parent-child releation ship between the TCCL (Web) and the
        ClassLoader of the JCA Adapter. You would still take the TCCL in this case.
        There would be no implementation available in the TCCL from the Web container
        that would implement the Log interface from the JCA Container. It would never work!

        The getBaseClassLoader method would return the TCCL if no base is found. You
        should add another loop that explictly tries the thisClassLoader if the TCCL is
        unsuccessful.

        If you add this, then it should work in nearlly every case

        Show
        Michael Kopp added a comment - Thanks for the fast reply. I checked the current trunk and unfortunatelly I do not think that the changes help. Consider you have a cross Container call (WebContainer to JCA Container of another Application). There is not parent-child releation ship between the TCCL (Web) and the ClassLoader of the JCA Adapter. You would still take the TCCL in this case. There would be no implementation available in the TCCL from the Web container that would implement the Log interface from the JCA Container. It would never work! The getBaseClassLoader method would return the TCCL if no base is found. You should add another loop that explictly tries the thisClassLoader if the TCCL is unsuccessful. If you add this, then it should work in nearlly every case
        Hide
        Simon Kitching added a comment -

        Thanks for reporting this, and for your proposed code.

        I believe that this functionality has already been added to the commons-logging
        trunk. See the current release notes for details:
        http://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk/RELEASE-NOTES.txt

        Hopefully a commons-logging 1.1 release isn't too far away - though that depends
        on how much time the committers on commons-logging can find.

        If you could download and compile the latest commons-logging code, and see if it
        resolves your issue that would definitely be appreciated. If it does, then
        please close this entry.

        In future, providing a patch file (ie generated by "svn diff" or "diff -u")
        would be appreciated instead of (or as well as) a full source code attachment.
        It's hard to see what changes you might have made by looking at the the attached
        file.

        Thanks again.

        Show
        Simon Kitching added a comment - Thanks for reporting this, and for your proposed code. I believe that this functionality has already been added to the commons-logging trunk. See the current release notes for details: http://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk/RELEASE-NOTES.txt Hopefully a commons-logging 1.1 release isn't too far away - though that depends on how much time the committers on commons-logging can find. If you could download and compile the latest commons-logging code, and see if it resolves your issue that would definitely be appreciated. If it does, then please close this entry. In future, providing a patch file (ie generated by "svn diff" or "diff -u") would be appreciated instead of (or as well as) a full source code attachment. It's hard to see what changes you might have made by looking at the the attached file. Thanks again.
        Hide
        Michael Kopp added a comment -

        Created an attachment (id=15695)
        proposed patch

        Show
        Michael Kopp added a comment - Created an attachment (id=15695) proposed patch

          People

          • Assignee:
            Unassigned
            Reporter:
            Michael Kopp
          • Votes:
            1 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development