Bug 34185 - Requirement: Combine JCL and UGLI
Summary: Requirement: Combine JCL and UGLI
Status: RESOLVED FIXED
Alias: None
Product: Log4j - Now in Jira
Classification: Unclassified
Component: Other (show other bugs)
Version: 1.3alpha
Hardware: All All
: P5 normal
Target Milestone: ---
Assignee: log4j-dev
URL:
Keywords: PatchAvailable
Depends on:
Blocks:
 
Reported: 2005-03-25 22:06 UTC by Boris Unckel
Modified: 2005-05-11 22:04 UTC (History)
1 user (show)



Attachments
UgliFactory extends org.apache.commons.logging.LogFactory.LogFactory (3.12 KB, text/plain)
2005-03-26 11:09 UTC, Boris Unckel
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Boris Unckel 2005-03-25 22:06:27 UTC
Due to beginning and ongoing discussions on both logging mailing lists I thougt
it is good to provide some example how near a possible solution is.
The code below does not solve any of the problems in JCL regarding ClassLoading
and dynamic lookup.

The idea is to ship an possible integration of Jakarta Commons Logging (JCL) and
the new Log4j Logging Wrapper UGLI. I can offer to make this part "production
ready" (Solid order of methods, JavaDoc, packaging...) if current project
leaders give a "go".

This is just demo code, it is placed in ASF Bugzilla to make it easy to find.

Below:
1) modified interface ULogger
2) modified SimpleLogger
3) modified NOPLogger
4) modified JDK14Logger

Missing
5) modified org.apache.log4j.Logger (just 4 methods, but the code
below shows how easy integration is...)


package org.apache.ugli;

/**
 * 
 * The main user inteface to logging. It is expected that logging takes places
 * through concerete implemetations of the ULogger interface.
 * 
 * 
 * @author Ceki Gülcü
 */
public interface ULogger extends org.apache.commons.logging.Log {

	public void trace(Object parameterizedMsg, Object param1);

	public void trace(Object parameterizedMsg, Object param1, Object param2);
	
	
	/**
	 * Log a parameterized message object at the DEBUG level.
	 * 
	 * <p>
	 * This form is useful in avoiding the superflous object creation problem
	 * when invoking this method while it is disabled.
	 * </p>
	 * 
	 * @param parameterizedMsg -
	 *            the parameterized message object
	 * @param param1 -
	 *            the parameter
	 */
	public void debug(Object parameterizedMsg, Object param1);

	/**
	 * Log a parameterized message object at the DEBUG level.
	 * 
	 * <p>
	 * This form is useful in avoiding the superflous object creation problem
	 * when invoking this method while it is disabled.
	 * </p>
	 * 
	 * @param parameterizedMsg -
	 *            the parameterized message object
	 * @param param1 -
	 *            the first parameter
	 * @param param2 -
	 *            the second parameter
	 */
	public void debug(Object parameterizedMsg, Object param1, Object param2);
	
	public void info(Object parameterizedMsg, Object param1);

	public void info(Object parameterizedMsg, Object param1, Object param2);

	public void warn(Object parameterizedMsg, Object param1);

	public void warn(Object parameterizedMsg, Object param1, Object param2);

	public void error(Object parameterizedMsg, Object param1);

	public void error(Object parameterizedMsg, Object param1, Object param2);

	public void fatal(Object parameterizedMsg, Object param1);

	public void fatal(Object parameterizedMsg, Object param1, Object param2);

	
}
//End of class ULogger


package org.apache.ugli.impl;

import org.apache.ugli.ULogger;

/**
 * A no operation (NOP) implementation of {@link ULogger}.
 * 
 * @author Ceki G&uuml;lc&uuml;
 */
public class NOPLogger implements ULogger {

	/**
	 * The unique instance of NOPLogger.
	 */
	public final static NOPLogger NOP_LOGGER = new NOPLogger();

	/**
	 * There is no point in people creating multiple instances of NullLogger.
	 * Hence, the private access modifier.
	 */
	private NOPLogger() {
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.ugli.Logger#isDebugEnabled()
	 */
	public boolean isDebugEnabled() {
		return false;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#debug(java.lang.Object)
	 */
	public void debug(Object msg) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#debug(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void debug(Object parameterizedMsg, Object param1, Object param2) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#debug(java.lang.Object, java.lang.Throwable)
	 */
	public void debug(Object msg, Throwable t) {
		// NOP
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.ugli.Logger#isInfoEnabled()
	 */
	public boolean isInfoEnabled() {
		// NOP
		return false;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#info(java.lang.Object)
	 */
	public void info(Object msg) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#info(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void info(String parameterizedMsg, Object param1, Object param2) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#info(java.lang.Object, java.lang.Throwable)
	 */
	public void info(Object msg, Throwable t) {
		// NOP
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.ugli.Logger#isWarnEnabled()
	 */
	public boolean isWarnEnabled() {
		return false;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#warn(java.lang.Object)
	 */
	public void warn(Object msg) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#warn(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void warn(String parameterizedMsg, Object param1, Object param2) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#warn(java.lang.Object, java.lang.Throwable)
	 */
	public void warn(Object msg, Throwable t) {
		// NOP
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.ugli.Logger#isErrorEnabled()
	 */
	public boolean isErrorEnabled() {
		return false;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#error(java.lang.Object)
	 */
	public void error(Object msg) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#error(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void error(String parameterizedMsg, Object param1, Object param2) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.Logger#error(java.lang.Object, java.lang.Throwable)
	 */
	public void error(Object msg, Throwable t) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#debug(java.lang.String, java.lang.Object)
	 */
	public void debug(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#error(java.lang.String, java.lang.Object)
	 */
	public void error(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#fatal(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void fatal(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#fatal(java.lang.String, java.lang.Object)
	 */
	public void fatal(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#info(java.lang.String, java.lang.Object)
	 */
	public void info(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#trace(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void trace(Object parameterizedMsg, Object param1, Object param2) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#trace(java.lang.String, java.lang.Object)
	 */
	public void trace(Object parameterizedMsg, Object param1) {
		// NOP
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#warn(java.lang.String, java.lang.Object)
	 */
	public void warn(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void fatal(Object message, Throwable t) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object)
	 */
	public void fatal(Object message) {
		// NOP

	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.commons.logging.Log#isFatalEnabled()
	 */
	public boolean isFatalEnabled() {
		return false;
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.commons.logging.Log#isTraceEnabled()
	 */
	public boolean isTraceEnabled() {
		return false;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void trace(Object message, Throwable t) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object)
	 */
	public void trace(Object message) {
		// NOP
	}

	/**
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#error(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void error(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

	/**
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#info(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void info(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

	/**
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#warn(java.lang.Object, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void warn(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

}
//End of class NOPLogger


import org.apache.ugli.ULogger;

/**
 * A simple implementation that logs messages of level INFO or higher on the
 * console (<code>System.out<code>). 
 * <p>
 * The output includes the relative time in milliseconds, thread name, the level,  
 * logger name, and the message followed by the line separator for the host. 
 * In log4j terms it amounts to the "%r  [%t] %level %logger - %m%n" pattern.
 * <pre>
 * 
 *           
 *   176 [main] INFO examples.Sort - Populating an array of 2 elements in
reverse order.
 *   225 [main] INFO examples.SortAlgo - Entered the sort method.
 *   304 [main] INFO SortAlgo.DUMP - Dump of interger array:
 *   317 [main] INFO SortAlgo.DUMP - Element [0] = 0
 *   331 [main] INFO SortAlgo.DUMP - Element [1] = 1
 *   343 [main] INFO examples.Sort - The next log statement should be an error
message.
 *   346 [main] ERROR SortAlgo.DUMP - Tried to dump an uninitialized array.
 *   at org.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
 *   at org.log4j.examples.Sort.main(Sort.java:64)
 *   467 [main] INFO  examples.Sort - Exiting main method.
 *            
 *   
 *  
 * </pre>
 * 
 * @author Ceki G&uuml;lc&uuml;
 */
public class SimpleLogger implements ULogger {

	String loggerName;

	/**
	 * Mark the time when this class gets loaded into memory.
	 */
	static private long startTime = System.currentTimeMillis();

	public static final String LINE_SEPARATOR = System
			.getProperty("line.separator");

	static private String INFO_STR = "INFO";

	static private String WARN_STR = "WARN";

	static private String ERROR_STR = "ERROR";

	/**
	 * Package access allows only {@link SimpleLoggerFA} to instantiate
	 * SimpleLogger instances.
	 */
	SimpleLogger(String name) {
		this.loggerName = name;
	}

	/**
	 * This is our internal implementation for logging regular
	 * (non-parameterized) log messages.
	 * 
	 * @param level
	 * @param message
	 * @param t
	 */
	private void log(String level, String message, Throwable t) {
		StringBuffer buf = new StringBuffer();

		long millis = System.currentTimeMillis();
		buf.append(millis - startTime);

		buf.append(" [");
		buf.append(Thread.currentThread().getName());
		buf.append("] ");

		buf.append(level);
		buf.append(" ");

		buf.append(loggerName);
		buf.append(" - ");

		buf.append(message);

		buf.append(LINE_SEPARATOR);

		System.out.print(buf.toString());
		if (t != null) {
			t.printStackTrace(System.out);
		}
		System.out.flush();
	}
	private String formatObject(Object parameterizedMsg, Object param1,
			Object param2) {
		String formatedString = null;
		if (parameterizedMsg instanceof String) {
			try {
				String msgStr = (String) parameterizedMsg;
				msgStr = MessageFormatter.format(msgStr, param1, param2);
			} catch (RuntimeException e) {
				formatedString = improveFormatObject(parameterizedMsg, param1,
						param2);
			}

		} else {
			// To be failsafe, we handle the case where 'messagePattern' is
			// not a valid String. Unless the user makes a mistake, this should
			// not happen.
			formatedString = improveFormatObject(parameterizedMsg, param1,
					param2);
		}
		return formatedString;
	}

	private String improveFormatObject(Object parameterizedMsg,
			Object param1, Object param2) {
		StringBuffer myBuf = new StringBuffer(String.valueOf(parameterizedMsg));
		myBuf.append("[");
		myBuf.append(param1);
		myBuf.append("]");
		if (param2 != null) {
			myBuf.append("[");
			myBuf.append(param2);
			myBuf.append("]");
		}
		return myBuf.toString();
	}
	/**
	 * For parameterized messages, first substitute parameters and then log.
	 * 
	 * @param level
	 * @param parameterizedMsg
	 * @param param1
	 * @param param2
	 */
	private void parameterizedLog(String level, Object parameterizedMsg,
			Object param1, Object param2) {
		String msgString = formatObject(parameterizedMsg, param1, param2);	
		log(level, msgString, null);
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#debug(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void debug(Object message, Throwable t) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#debug(java.lang.Object)
	 */
	public void debug(Object message) {
		// NOP

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.commons.logging.Log#error(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void error(Object message, Throwable t) {
		log(ERROR_STR, String.valueOf(message), t);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.commons.logging.Log#error(java.lang.Object)
	 */
	public void error(Object message) {
		log(ERROR_STR, String.valueOf(message), null);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void fatal(Object message, Throwable t) {
		log(ERROR_STR, String.valueOf(message), t);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.commons.logging.Log#fatal(java.lang.Object)
	 */
	public void fatal(Object message) {
		log(ERROR_STR, String.valueOf(message), null);

	}

	/*
	 * @see org.apache.commons.logging.Log#info(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void info(Object message, Throwable t) {
		log(INFO_STR, String.valueOf(message), t);

	}

	/*
	 * @see org.apache.commons.logging.Log#info(java.lang.Object)
	 */
	public void info(Object message) {
		log(INFO_STR, String.valueOf(message), null);

	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.commons.logging.Log#isDebugEnabled()
	 */
	public boolean isDebugEnabled() {
		return false;
	}

	/*
	 * Always returns true.
	 * 
	 * @see org.apache.commons.logging.Log#isErrorEnabled()
	 */
	public boolean isErrorEnabled() {
		return true;
	}

	/*
	 * Always returns true.
	 * 
	 * @see org.apache.commons.logging.Log#isFatalEnabled()
	 */
	public boolean isFatalEnabled() {
		return true;
	}

	/*
	 * Always returns true.
	 * 
	 * @see org.apache.commons.logging.Log#isInfoEnabled()
	 */
	public boolean isInfoEnabled() {
		return true;
	}

	/*
	 * Always returns false.
	 * 
	 * @see org.apache.commons.logging.Log#isTraceEnabled()
	 */
	public boolean isTraceEnabled() {
		return false;
	}

	/*
	 * Always returns true.
	 * 
	 * @see org.apache.commons.logging.Log#isWarnEnabled()
	 */
	public boolean isWarnEnabled() {
		return true;
	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void trace(Object message, Throwable t) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.commons.logging.Log#trace(java.lang.Object)
	 */
	public void trace(Object message) {
		// NOP

	}

	/*
	 * @see org.apache.commons.logging.Log#warn(java.lang.Object,
	 *      java.lang.Throwable)
	 */
	public void warn(Object message, Throwable t) {
		log(ERROR_STR, String.valueOf(message), t);

	}

	/*
	 * @see org.apache.commons.logging.Log#warn(java.lang.Object)
	 */
	public void warn(Object message) {
		log(WARN_STR, String.valueOf(message), null);

	}

	/*
	 * @see org.apache.ugli.ULogger#debug(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void debug(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

	/*
	 * @see org.apache.ugli.ULogger#debug(java.lang.String, java.lang.Object)
	 */
	public void debug(Object parameterizedMsg, Object param1) {
		// NOP

	}

	/*
	 * @see org.apache.ugli.ULogger#error(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void error(Object parameterizedMsg, Object param1, Object param2) {
		parameterizedLog(ERROR_STR, parameterizedMsg, param1, param2);

	}

	/*
	 * @see org.apache.ugli.ULogger#error(java.lang.String, java.lang.Object)
	 */
	public void error(Object parameterizedMsg, Object param1) {
		parameterizedLog(ERROR_STR, parameterizedMsg, param1, null);

	}

	/*
	 * @see org.apache.ugli.ULogger#fatal(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void fatal(Object parameterizedMsg, Object param1, Object param2) {
		parameterizedLog(ERROR_STR, parameterizedMsg, param1, param2);

	}

	/*
	 * @see org.apache.ugli.ULogger#fatal(java.lang.String, java.lang.Object)
	 */
	public void fatal(Object parameterizedMsg, Object param1) {
		parameterizedLog(ERROR_STR, parameterizedMsg, param1, null);

	}

	/*
	 * @see org.apache.ugli.ULogger#info(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void info(Object parameterizedMsg, Object param1, Object param2) {
		parameterizedLog(INFO_STR, parameterizedMsg, param1, param2);

	}

	/*
	 * @see org.apache.ugli.ULogger#info(java.lang.String, java.lang.Object)
	 */
	public void info(Object parameterizedMsg, Object param1) {
		parameterizedLog(INFO_STR, parameterizedMsg, param1, null);

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#trace(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void trace(Object parameterizedMsg, Object param1, Object param2) {
		// NOP

	}

	/*
	 * A NOP implementation.
	 * 
	 * @see org.apache.ugli.ULogger#trace(java.lang.String, java.lang.Object)
	 */
	public void trace(Object parameterizedMsg, Object param1) {
		// NOP
	}

	/*
	 * @see org.apache.ugli.ULogger#warn(java.lang.String, java.lang.Object,
	 *      java.lang.Object)
	 */
	public void warn(Object parameterizedMsg, Object param1, Object param2) {
		parameterizedLog(WARN_STR, parameterizedMsg, param1, param2);

	}

	/*
	 * @see org.apache.ugli.ULogger#warn(java.lang.String, java.lang.Object)
	 */
	public void warn(Object parameterizedMsg, Object param1) {
		parameterizedLog(WARN_STR, parameterizedMsg, param1, null);

	}

}
//End of class SimpleLogger

import org.apache.ugli.ULogger;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A wrapper over
 * 
 * @{link java.utill.Logger} which conforms to the {@link ULogger} interface.
 * 
 * @author Ceki G&uuml;lc&uuml;
 */
public class JDK14Logger implements ULogger {
	final Logger logger;

	// WARN: JDK14Logger constructor should have only package access so that
	// only JDK14LoggerFA be able to create one.
	JDK14Logger(Logger logger) {
		this.logger = logger;
	}

	private String formatObject(Object parameterizedMsg, Object param1,
			Object param2) {
		String formatedString = null;
		if (parameterizedMsg instanceof String) {
			try {
				String msgStr = (String) parameterizedMsg;
				msgStr = MessageFormatter.format(msgStr, param1, param2);
			} catch (RuntimeException e) {
				formatedString = improveFormatObject(parameterizedMsg, param1,
						param2);
			}

		} else {
			// To be failsafe, we handle the case where 'messagePattern' is
			// not a valid String. Unless the user makes a mistake, this should
			// not happen.
			formatedString = improveFormatObject(parameterizedMsg, param1,
					param2);
		}
		return formatedString;
	}

	private String improveFormatObject(Object parameterizedMsg,
			Object param1, Object param2) {
		StringBuffer myBuf = new StringBuffer(String.valueOf(parameterizedMsg));
		myBuf.append("[");
		myBuf.append(param1);
		myBuf.append("]");
		if (param2 != null) {
			myBuf.append("[");
			myBuf.append(param2);
			myBuf.append("]");
		}
		return myBuf.toString();
	}

	public void trace(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.FINEST)) {
			String msgStr = formatObject(parameterizedMsg, param1, null);
			logger.finest(msgStr);
		}
	}

	public void trace(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.finest(msgStr);
	}

	public void debug(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.FINE)) {
			String msgStr = formatObject(parameterizedMsg, param1, null);
			logger.fine(msgStr);
		}
	}

	public void debug(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.fine(msgStr);
	}

	public void info(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.INFO)) {
			String msgStr = (String) parameterizedMsg;
			msgStr = MessageFormatter.format(msgStr, param1);
			logger.info(msgStr);
		}
	}

	public void info(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.info(msgStr);
	}

	public void warn(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.WARNING)) {
			String msgStr = formatObject(parameterizedMsg, param1, null);
			logger.warning(msgStr);
		}
	}

	public void warn(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.warning(msgStr);
	}

	public void error(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.SEVERE)) {
			String msgStr = formatObject(parameterizedMsg, param1, null);
			logger.severe(msgStr);
		}
	}

	public void error(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.severe(msgStr);
	}

	public void fatal(Object parameterizedMsg, Object param1) {
		if (logger.isLoggable(Level.SEVERE)) {
			String msgStr = formatObject(parameterizedMsg, param1, null);
			logger.severe(msgStr);
		}
	}

	public void fatal(Object parameterizedMsg, Object param1, Object param2) {
		String msgStr = formatObject(parameterizedMsg, param1, param2);
		logger.severe(msgStr);
	}

	public boolean isDebugEnabled() {
		return logger.isLoggable(Level.FINE);
	}

	public boolean isErrorEnabled() {
		return logger.isLoggable(Level.SEVERE);
	}

	public boolean isFatalEnabled() {
		return logger.isLoggable(Level.SEVERE);
	}

	public boolean isInfoEnabled() {
		return logger.isLoggable(Level.INFO);
	}

	public boolean isTraceEnabled() {
		return logger.isLoggable(Level.FINEST);
	}

	public boolean isWarnEnabled() {
		return logger.isLoggable(Level.WARNING);
	}

	public void trace(Object message) {
		logger.finest(String.valueOf(message));
	}

	public void trace(Object message, Throwable t) {
		logger.log(Level.FINEST, String.valueOf(message), t);
	}

	public void debug(Object message) {
		logger.fine(String.valueOf(message));

	}

	public void debug(Object message, Throwable t) {
		logger.log(Level.FINE, String.valueOf(message), t);

	}

	public void info(Object message) {
		logger.info(String.valueOf(message));

	}

	public void info(Object message, Throwable t) {
		logger.log(Level.INFO, String.valueOf(message), t);

	}

	public void warn(Object message) {
		logger.warning(String.valueOf(message));

	}

	public void warn(Object message, Throwable t) {
		logger.log(Level.WARNING, String.valueOf(message), t);

	}

	public void error(Object message) {
		logger.severe(String.valueOf(message));

	}

	public void error(Object message, Throwable t) {
		logger.log(Level.SEVERE, String.valueOf(message), t);
	}

	public void fatal(Object message) {
		logger.severe(String.valueOf(message));

	}

	public void fatal(Object message, Throwable t) {
		logger.log(Level.SEVERE, String.valueOf(message), t);

	}

}
//End of class JDK14Logger
Comment 1 Yoav Shapira 2005-03-25 22:14:21 UTC
I dislike the word "requirement" in a Bugzilla issue ;(
Comment 2 robert burrell donkin 2005-03-25 22:40:54 UTC
FWIW issues like this have been discussed at length on the jakarta commons list.
I thought it might save a little time if I were to point out the tricky bit of
any JCL redesign.

The key design mistake made when JCL was created was not the much-malined
dynamic discovery mechanism, it was the fact that LogFactory is too tightly
coupled to the discovery mechanism. It would be possible to extract an interface
modelled as an abstract superclass containing the user-facing API from
LogFactory and retrofit a minimal implementation lookup mechanism with no
complex discovery. This would allow refitting of new binding mechanisms whilst
maintaining backwards compatibility. 

Had the storm not blown up about the current JCL implementation, this was the
direction which the JCL2 codebase would have taken. 
Comment 3 Jacob Kjome 2005-03-26 05:43:45 UTC
Hmmm....

I mentioned something very similar, only exactly opposite, in my email response
to Simon Kitching.

This...
public interface ULogger extends org.apache.commons.logging.Log

Becomes this...
public interface org.apache.commons.logging.Log extends ULogger


It doesn't make sense for a logging implementation which commons-logging wraps,
such as Log4j, to have a dependency on commons-logging itself, which it would by
its implementation of UGLI.  Having commons-logging implement UGLI (or whatever
name it ends up as) also solves an issue with coordination of projects.  Simon
Kitching mentioned that it will be 2 or 3 months before JCL 2.0 becomes more
than an idea.  UGLI exists now, Log4j implements it, and Log4j-1.3 is
tentatively scheduled to be released around the time where JCL 2.0 will be just
getting off the ground.  The JCL team also has requirements such as backward
compatibility and the extension of their own API with new functionality.  If we
can all agree on a base logging API, then everyone can simply agree to implement
it and take as much time as they want.  Existing API's shouldn't have to change
much (if at all) and extention of the API's can be done at will.

A change like this would allow commons-logging users the option to either
continue to use the JCL API or move to the UGLI API.  In the case where they
choose the UGLI API, they can choose any implementation that implements the UGLI
API, including Log4j, JCL, NOP, Simple, and even choose an UGLI wrapper such as
the UGLI JUL wrapper implementation.  All API's become compatible and users can
choose which implementation of UGLI meets their needs the best.  I don't think
anyone loses here.

UGLI can stay "UGLI" or become something like "Apache Logging API, or "ALAPI". 
Whatever name is chosen, the point is that its interface becomes the standard
for everyone.

Thoughts?


Jake
Comment 4 Boris Unckel 2005-03-26 08:21:56 UTC
(In reply to comment #3)
> I mentioned something very similar, only exactly opposite, in my email response
> to Simon Kitching.
Yes, I have read that mail.
> This...
> public interface ULogger extends org.apache.commons.logging.Log
> 
> Becomes this...
> public interface org.apache.commons.logging.Log extends ULogger
> 
> 
> It doesn't make sense for a logging implementation which commons-logging wraps,
> such as Log4j, to have a dependency on commons-logging itself, which it would by
> its implementation of UGLI.  
I think one has to small steps, even for getting acceptance. UGLI is out as
alpha. UGLI (or better log4j 1.3) introduce multiple jars (I know that solves
problems and is a good idea, but for users this is a eye-catching change), and
users have to code different to use it. I think it should be no problem to
package the interface (not the whole JCL) with log4j. 
For me UGLI is an wrapper, and it will be wide spread due to the popularity of
log4j. Once introduced it will be hard to change.
To have an interim solution JCL's Factory could be changed to the static binding
and an configuration only (without classloading isues) lookup.



>Having commons-logging implement UGLI (or whatever
> name it ends up as) also solves an issue with coordination of projects.  
Sounds not like a win-win to me. 
> Simon
> Kitching mentioned that it will be 2 or 3 months before JCL 2.0 becomes more
> than an idea.  
What kind of feature should JCL 2.0 offer, if it is done like you described?
Just my first impression, I still want to disuss factually: JCL==YAUGLI, yet
another...
> UGLI exists now, Log4j implements it, and Log4j-1.3 is
JCL exists now, Wrappers are existing, major applications use it.

> tentatively scheduled to be released around the time where JCL 2.0 will be just
> getting off the ground.  
Yes, correct, so we there is a need to get ideas to solve this time gap.
> The JCL team also has requirements such as backward
> compatibility and the extension of their own API with new functionality.  
UGLI has no backward compatibility issues and contains new functionality.
> If we
> can all agree on a base logging API, then everyone can simply agree to implement
> it and take as much time as they want.  Existing API's shouldn't have to change
> much (if at all) and extention of the API's can be done at will.



> A change like this would allow commons-logging users the option to either
Sorry, maybe I am not wide awake - what is "this"? Your proposal or the demo code?

> continue to use the JCL API or move to the UGLI API.  In the case where they
> choose the UGLI API, they can choose any implementation that implements the UGLI
> API, including Log4j, JCL, NOP, Simple, and even choose an UGLI wrapper such as
> the UGLI JUL wrapper implementation.  
The idea of wrapping and having the choice is the major goal of JCL and main
succesing feature.

The demo code should just show how less change in UGLI is necessary to become an
integration of JCL. Next changes have to be done in JCL.


Boris
Comment 5 Boris Unckel 2005-03-26 11:09:08 UTC
Created attachment 14568 [details]
UgliFactory extends org.apache.commons.logging.LogFactory.LogFactory

This factory whould implement a backward compatible version of the JCL
LogFactory.
If one is convinced this could be the default Factory for JCL. All
configuration issues would occur at Ugli. This also could be a migration path.

It depends on ULogger extends org.apache.commons.logging.Log as published in
this Bugzilla.

Comments?
Comment 6 robert burrell donkin 2005-03-26 11:19:46 UTC
FWIW 

I've analysed these issues in depth and believe that subclassing will not prove
effective due to the coupling problems I indicated above. A better path would be
to extract an abstract superclass as part of JCL and subclass that instead. JCL
will probably go down this route in any case. 


Comment 7 robert burrell donkin 2005-03-31 22:44:18 UTC
I thought an example would be useful :)

So, I've create a branch in jakarta/commons/logging called DON_QUIXOTE and added
some example code into their. This lifts off a superclass called LogManager (for
no very good reason) from LogFactory. The most common user method (getLog) is
rewired so that it first calls the superclass. When LogFactory is in the same
classloader (ideally in the same jar) as LogManager, the call will be routed
through LogFactory. This preserves backwards compatibility.

This is the way that Richard and I saw JCL2 proceeding.

An option which you may want to consider is compile-time statically binding an
alternative LogManager implementation to UGLI. This (I believe) would in line
with the spirit of the UGLI way whilst also ensure no actual core dependencies
either way.

If anyone feels this sounds like a reasonable approach and would like to take a
look at creating some experimental implementation code along those lines, I'd be
glad to review it for possible inclusion in the branch. 

I'm don't intend to particularly push this solution (UGLI is the responsibility
of others) but I think it's important that all possible solutions are considered.

Robert
Comment 8 Curt Arnold 2005-05-12 06:04:49 UTC
UGLI development has been moved to http://www.slf4j.org.