Configuration And Discovery
Configuration and discovery is the process used by commons-logging to determine the correct Log implementation to call.
The Current Situation
Discover And Configuration
Code calls the commons-logging API to request a Log instances. This call is made to a LogFactory class method. This class method attempts to discover which LogFactory instance should be used to service this request. This discovery process involves various classloader gymnastics intended to give correct isolation for applications run in certain container environments.
These gymnastics work well in only a limited number of container environments. There is a definite limit to the improvements that can be made to this discovery code whilst it is contained with an API class. The code is also both complex and fragile.
There is no compile time dependency from the API classes to the implementation ones. However, it is not practical to distribution the implementation code separately from the API since the API code will fail unless the implementation classes are present.
A Road Forward
(I'll try to present not the results but the reasoning which lead in this direction. Hopefully, this should make it easier for the community to understand, involve itself and find any better alternative routes that have been missed.)
It is generally acknowledge that commons logging needs a small, functional API for components to compile and run against. LogFactory is too complex. It includes complex discovery code which limits the usefulness of subclassing. (For example, for use in a J2ME environment.) It's size limits it's usefulness in applets.
A suitable API layer could be created by pushing the discovery code (includig LogFactory) into a separate, subsidary layer. The role of LogFactory in the API would be replaced by a small, simple class called Logger, say.
The discovery process has many problems. The current implementation works well in some containers, less well in other containers and not at all in some environments. It has become clear that no one discovery mechanism can work well in the range of environments in which commons-logging may find itself deployed. This points towards a need for the discovery mechanism to be pluggable.
The process of discovery should be encapsulated entirely within the discovery layer. Therefore, there seems to be nothing to gain by adding a separate interface for discovery. So, the discovery component should have a facade which extends Logger.
The choice of the appropriate discovery implementation should be common throughout a particular environment. For example, though a discovery implementation that knows how to isolate applications is needed for a container environment, there is no need for the discovery process to vary per application. Therefore, the neccessary configuration can be stripped down to the minimal: a system property. This would give the name of the Logger implementation to be loaded and used.
Backwards compatibility could be maintained by defaulting to the use of LogFactory when this class is present and no other configuration is. By making Logger a superclass of LogFactory, it should be possible to use the existing system property without breaking existing systems. New discovery mechanisms could override Logger (rather than the bulkier LogFactory).
The current API is that it is not useable by itself at run time by itself: it fails when suitable implementations cannot be discovered. This dramatically increases the effective size of a runnable API jar. Since the dominent paradigm involves hold Log references as class variables, this behaviour can be very annoying at times since classes cannot be loaded unless commons logging is correctly configured. So, rather than fail, Logger should provide some sort of very basic Log even when no system property has been set and LogFactory cannot be loaded. This would probably log messages with Error and Fatal serverity to System.err.
The Logger API should be minimal and compact. The current LogFactory provides a number of methods which are small variations on each other. These can and should be consolidated. The primary use case for Logger is to provide a log appropriate for a configuration. The use of Class (in addition to String) has proved a useful innovation. I propose that Logger extends this further by allowing any object to be passed in. The discovery layer would have the freedom to process these in whatever fashion they choose. The LogFactory implementation would convert all objects toString other than Class's.
We therefore arrive at the following signature for Logger:
public static final Log Logger.getLog(Object parameter) throws LogConfigurationException public Log getLog(Object parameter) throws LogConfigurationException
Up to Logging