cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mike Wilson <mike...@hotmail.com>
Subject RE: avoid using contextClassLoader inside OSGi?
Date Fri, 27 Feb 2015 16:10:08 GMT
Right, this sounds fair. If you (or the things you call) need to do
classname->class lookups then some kind of classloader context is needed and
TCCL is the JEE way..
So what remains then is to constrain TCCL setup to only the places where it
is really needed. Below I describe the Pax/Juli bug that appears when
looking up loggers with TCCL set. 
TL;DR: TCCL should not be set while executing getLogger(name) in an
OSGi/PaxLogging/Juli context.

CONFIGURATION
-------------

System classpath contains:
    juli logging

Karaf bundles:
    pax logging 
    cxf
    mycxfbundle

Karaf logging config in etc/org.ops4j.pax.logging.cfg:
    log4j.appender.cxf.file=cxf.log
    log4j.logger.org.apache.cxf.services=INFO,cxf

WHAT HAPPENS AT DIFFERENT LEVELS
--------------------------------

MYCXFBUNDLE
Calling method on generated API to send WS message:
myCxfApi.sayHello();

CXF
Interceptor executed as part of message handling:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-bundle/2.
7.14/org/apache/cxf/transport/ChainInitiationObserver.java
org.apache.cxf.transport.ChainInitiationObserver
    ChainInitiationObserver(...)
        // In OSGi the loader is set to an instance of
org.apache.cxf.bus.blueprint.BundleDelegatingClassLoader
        loader = bus.getExtension(ClassLoader.class);
    onMessage(Message) 
        if (loader != null) {
            // Now TCCL is assigned to the BundleDelegatingClassLoader
            origLoader =
ClassLoaderUtils.setThreadContextClassloader(loader);
        }

Logging interceptor executed a bit further down the stack:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-bundle/2.
7.14/org/apache/cxf/interceptor/LoggingInInterceptor.java
org.apache.cxf.interceptor.LoggingInInterceptor
    // The class's own logger will route through Pax's handler as it is
looked 
    // up while TCCL is null
    LOG = LogUtils.getLogger(LoggingInInterceptor.class)
    handleMessage(...)
        // This logger will route through Juli's handler as it is looked up 
        // while TCCL is set
        Logger logger = getMessageLogger(message)

PAX
This is how Pax Logging hooks into j.u.l logging used by CXF:
http://grepcode.com/file/repo1.maven.org/maven2/org.ops4j.pax.logging/pax-lo
gging-service/1.8.1/org/ops4j/pax/logging/service/internal/Activator.java
org.ops4j.pax.logging.service.internal.Activator
    start()
        // TCCL is not set so this RootLogger will be located in the system 
        // classloader section below where most bundles will also look
        Logger rootLogger = manager.getLogger( "" );
        ...
        m_JdkHandler = new JdkHandler( m_PaxLogging );
        rootLogger.addHandler( m_JdkHandler );

JULI
Further down in the call hierarchy the lookup for a logger arrives in Juli:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomc
at-embed-logging-juli/8.0.15/org/apache/juli/ClassLoaderLogManager.java 
org.apache.juli.ClassLoaderLogManager
    getLogger(String name)
        // Juli partition loggers into different "domains" depending on TCCL
        ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
        return getClassLoaderInfo(classLoader).loggers.get(name);

    // The data structure that keeps the loggers will be populated like
this:
    classLoaderLoggers: {
        <system classloader>: { // key used when TCCL==null
            loggers: [
                // Almost all bundles' loggers will be found here
                "org.apache.cxf.interceptor.LoggingInInterceptor": Logger(no
handlers)
                ...
                // This RootLogger is the one Pax locates and patches to
route 
                // logging to its own handler
                "": RootLogger(handlers -> Pax)
            ]
        <mycxfbundle classloader>: { // TCCL was set so creates a new entry
            loggers: [
                "...mycxfbundle": Logger(no handlers)
                // This RootLogger is not found by Pax so it keeps its
default 
                // Juli settings
                "": RootLogger(handlers -> Juli)
            ]
        }
    } 

Best regards
Mike

Daniel Kulp wrote:
> > On Feb 26, 2015, at 4:04 PM, Mike Wilson 
> <mikewse@hotmail.com> wrote:
> > Having the luxury of not understanding the implications in 
> the CXF codebase
> > I would choose to disagree ;-), and welcome removal of TCCL 
> usage as it
> > seems not to be set in normal JEE scenarios and is only set 
> when running in
> > OSGi, where it is explicitly unrecommended to do so.
> 
> Well, no.  It's also set when using Spring to setup your 
> endpoints and services.   There are other cases where it's 
> set as well.
> 
> Most importantly, there are a BUNCH of places in CXF and in 
> the libraries that CXF uses that require it.   CXF being 
> primarily an implementation of J2EE specs in general uses the 
> recommendations and guidelines provided by J2EE which 
> includes the use of the TCCL.    In particular, things like 
> loading the JAX-WS handlers from the @HandlerChain would 
> require the use of the TCCL to locate and "newInstance" them. 
>   The xmlbeans and jibx data bindings would also require the 
> use of the TCCL for loading the various resources they need 
> to operate.   The WS-Security stuff we have may use the TCCL 
> to load callback objects (although some of them can be passed 
> by reference to a bean instead of just a class name).    Some 
> use of JAXB requires it (if you do a 
> JAXBContext.newInstance("com.foo.package") for example). 
> 
> Even some of the CXF annotations themselves would require it. 
>  For example, @Features(features = "org.apache.MyFeature") 
> would need it to load the appropriate feature.  (Although all 
> the CXF annotations that do this have an alternative form 
> that takes the class object itself that could be used 
> instead.  @Features(classes = MyFeature.class))
> 
> Some of them could be "fixed" by adding a bunch of 
> "ClassLoader"  parameters to various methods and passing that 
> around, but that's a massive change and also a complete hack 
> IMO.   The TCCL was created specifically for providing the 
> class loader of the current "context" to avoid having to do 
> all of that. 
> 
> Those are just a couple off the top of my head.    I'm sure 
> there are others.
> 
> Dan
> 
> 
> > Anyway, I'll put together a description of the bug and post 
> here (as it
> > seems this is where you prefer to do the discussion about it?).
> > 
> > Best regards
> > Mike
> > 
> > Sergey Beryozkin wrote:
> >> On 26/02/15 12:58, Mike Wilson wrote:
> >>> Ok, let's see if other believe TCCL usage is possible to 
> >> remove altogether.
> >>> If not, I'll invest the time to create a ticket with the 
> >> details of the bug.
> >>> 
> >>> In short, it happens when CXF logging is routed to Juli.
> >> Do you have more details re why it breaks with Juli involved 
> >> ? How does 
> >> CXF setting TCCL affects Juli doing its work ?
> >> 
> >> IMHO the best way to get it moved forward is to have a 
> concrete case 
> >> discussion (as Christian suggested) and see what can be done 
> >> it make it 
> >> resolved as opposed to just considering completely removing 
> >> the use of 
> >> TCCL - might be risky, though may be Christian and Dan may 
> >> have another 
> >> view with respect to using an OSGI-specific loader in the chain...
> >> 
> >> Cheers, Sergey
> >>> If configuring CXF
> >>> to route through Slf4j the problem goes away.
> >>> 
> >>> Best regards
> >>> Mike
> >>> 
> >>> Christian Schneider wrote:
> >>>> I think it might make sense to remove the TCCL usage in OSGi
> >>>> where ever
> >>>> possible. This is not a small thing though as we have to be
> >>>> careful not
> >>>> to break existing code.
> >>>> 
> >>>> So for short term it will make more sense to work around 
> >> the problem.
> >>>> Can you give a concrete example where it breaks for you?
> >>>> Btw. I am using pax logging a lot and itworks fine with CXF.
> >>>> I just use
> >>>> the slf4j API in my own code and pax logging implements it.
> >>>> 
> >>>> Christian
> >>>> 
> >>>> On 24.02.2015 15:46, Mike Wilson wrote:
> >>>>> Yes, the undesired side-effect for us is that the
> >>>> combination of CXF, Juli
> >>>>> and Pax Logging breaks down. Looking at the code it seems
> >>>> all involved
> >>>>> parties have design decisions done with good intentions 
> >> and the only
> >>>>> questionable thing is CXF's use of TCCL, which is sort of
> >>>> the trigger of the
> >>>>> problem. So I thought this would be the first thing worth
> >>>> considering as it
> >>>>> is advised against in OSGi.
> >>>>> 
> >>>>> If not possible to remove TCCL entirely, then it might
> >>>> still be possible to
> >>>>> only set it during the very calls into stuff that need it,
> >>>> instead of during
> >>>>> the whole message cycle?
> >>>>> 
> >>>>> Best regards
> >>>>> Mike
> >>>>> 
> >>>> 
> >>>> --
> >>>> Christian Schneider
> >>>> http://www.liquid-reality.de
> >>>> 
> >>>> Open Source Architect
> >>>> http://www.talend.com
> >>>> 
> >>>> 
> >>> 
> >> 
> >> 
> > 
> 
> -- 
> Daniel Kulp
> dkulp@apache.org - http://dankulp.com/blog
> Talend Community Coder - http://coders.talend.com
> 
> 


Mime
View raw message