You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Simon Kitching <sk...@apache.org> on 2006/03/02 04:05:28 UTC

[logging] proposal for JCL2 implementation

Hi All,

As you may have seen from the recent commit, I've added some code to
  proper/logging/contrib/simon/jcl2

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:
  core-static.jar:
    Log  (interface)
    LogHandler (interface)
    LogFactory (abstract class)
    LogFactoryStatic (concrete subclass of LogFactory)
    Utils (static utility class)
    META-INF/services/org.apache.commons.logging.LogFactory
     --> 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)
    META-INF/services/org.apache.commons.logging.LogFactory
     --> points to LogFactoryStatic

  noop.jar:
    NoOpLog
    NoOpLogHandler
    META-INF/services/org.apache.commons.logging.LogHandler
     --> points to NoOpLogHandler

  simple.jar
    SimpleLog
    SimpleLogHandler
    META-INF/services/org.apache.commons.logging.LogHandler
     --> points to SimpleLogHandler
    
   etc

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:
   LogFactory
   [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
class).

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.

Cheers,

Simon


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [logging] proposal for JCL2 implementation

Posted by Dennis Lundberg <de...@apache.org>.
Simon Kitching wrote:
> Hi All,

Simon,

Sorry for jumping in late...

While reading through the two JCL design threads an idea struck to me, 
similar to the one you are proposing here. I was thinking in terms of 
having a commons-logging.properties file bundled in each of the jar 
files. The effect would be the same, but I think your services approach 
is better.


> As you may have seen from the recent commit, I've added some code to
>   proper/logging/contrib/simon/jcl2
> 
> 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:
>   core-static.jar:
>     Log  (interface)
>     LogHandler (interface)
>     LogFactory (abstract class)
>     LogFactoryStatic (concrete subclass of LogFactory)
>     Utils (static utility class)
>     META-INF/services/org.apache.commons.logging.LogFactory
>      --> 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)
>     META-INF/services/org.apache.commons.logging.LogFactory
>      --> points to LogFactoryStatic
> 
>   noop.jar:
>     NoOpLog
>     NoOpLogHandler
>     META-INF/services/org.apache.commons.logging.LogHandler
>      --> points to NoOpLogHandler
> 
>   simple.jar
>     SimpleLog
>     SimpleLogHandler
>     META-INF/services/org.apache.commons.logging.LogHandler
>      --> points to SimpleLogHandler
>     
>    etc
> 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:
>    LogFactory
>    [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
> class).
> 
> 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.
> 
> Cheers,
> 
> Simon
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


-- 
Dennis Lundberg

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org