commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Kitching <>
Subject [logging] proposal for JCL2 implementation
Date Thu, 02 Mar 2006 03:05:28 GMT
Hi All,

As you may have seen from the recent commit, I've added some code to

Obviously this is very much work-in-progress; I've committed this really
to ensure I don't lose the stuff. I intend to do more testing on this
code to see if it stands up before seriously proposing this as a JCL2
architecture. However if anyone wishes to provide feedback at this very
early stage I'd be happy to see it.


Ok, you're still reading?? Well, then, here's the basic concepts.

This is the result of a idea that suddenly occurred to me. As far as I
can see, it results in pretty much the same effect as "static binding",
but needs no compilation or bytecode tricks at all.

Instead the code is based heavily around the standard "services" pattern
introduced in java1.3, though it should run on any version, together
with a few basic packaging rules that must be followed.

As always in such early code, the code and build process is a bit rough,
but it does build and run.

The resulting jars are:
    Log  (interface)
    LogHandler (interface)
    LogFactory (abstract class)
    LogFactoryStatic (concrete subclass of LogFactory)
    Utils (static utility class)
     --> points to LogFactoryStatic

  core-dynamic.jar: [not yet implemented :-]
    Log  (interface)
    LogHandler (interface)
    LogFactory (abstract class)
    LogFactoryStatic (concrete subclass of LogFactory)
    Utils (static utility class)
     --> points to LogFactoryStatic

     --> points to NoOpLogHandler

     --> points to SimpleLogHandler

A user would choose one of (core-static, core-dynamic) and then one of
(noop.jar, simple.jar, log4j.jar, jul.jar, whatever).
Directory "src/core" contains the traditional Log interface, almost
unchanged. It also contains a LogFactory abstract class which provides
the standard getLog(class) and getLog(string) methods; however rather
than implementing any logic itself it just delegates to an underlying
concrete subclass of LogFactory. So far, we've talked about all this
before and I believe hava consensus.

The interesting bit is the way that LogFactory determines which subclass
to instantiate and delegate to. It simply looks for file
"META-INF/services/org.apache.commons.logging.LogFactory" in the way
recommended for standard java Service Providers. As long as the
following files are *always* bundled together, I can't see any way to
get cross-wiring:
   [some LogFactory implementation]
   [the service file]

When a classloader is implementing "parent-first", then the LogFactory
found will not come from classloader X unless there is no such class in
any ancestor. Therefore when that class looks for the service file and
the specified implementation it should get the ones out of its own
jarfile (because they are never found without an accompanying LogFactory

When a classloader is implementing "child-first", then when the
LogFactory looks for the service file and the specified implementation
then they will be served from the same classloader.

Note that the lookup NEVER involves the TCCL; we're effectively trying
to treat the three files above as if they had been "statically merged"
into a single class so using the TCCL doesn't make sense. 

I believe the result is that we (and users) can provide variants on the
core classes simply by bundling the standard UNMODIFIED LogFactory class
with their own subclass and the appropriate service file to effectively
bind the two together. This makes the build process much cleaner than
the other options we were considering; probably even compatible with
maven2. All we do is duplicate (unmodified) classes
LogFactory/Log/LogHandler/Utils into each jar that provides a different
LogFactory concrete implementation.

The LogFactoryStatic implementation of LogFactory is one that locates
its log adapter class *without* using the TCCL, ie is suitable for apps,
applets etc. And it in turn uses the same standard java Service Provider
approach (META-INF/services) to locate the adapter.

I've introduced the new interface LogHandler; in the old version the
LogFactory class was essentially filling two purposes: implementing an
algorithm for finding a log implementation, and acting as a
logging-lib-specific factory for Log objects. These really need to be
separated. For binary compatibility, the abstract class the user
interacts with really needs to keep the LogFactory name, so I've used a
new name for the latter role.

And the resulting classes are much easier for users to understand; we
don't have classes with the same names but different implementations
floating around.



To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message