/**
* Copyright (C) 2001-2003 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.util.monolog.wrapper.common;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.Handler;
import org.objectweb.util.monolog.api.Level;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.MonologFactory;
import org.objectweb.util.monolog.api.MonologFactoryListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;
/**
*
* @author S.Chassande-Barrioz
*/
public abstract class AbstractFactory
implements MonologFactory, Configurable {
public final static String CLASSLOADER_ISOLATION = "monolog.isolateclassloader";
public static String[] handlerTypes = {
"console", "file", "rollingfile", "ntevent","jmx"
};
public static String[][] handlerType2className = null;
public static boolean classLoaderIsoltion = true;
/**
* Root logger prefix, i.e. <code>rootLoggerName</code> followed by '.'.
*/
protected static String rootLoggerPrefix = null;
/**
* Name of the root logger.
* This name intends to isolates the loggers associated to a class loader.
*/
protected static String rootLoggerName = null;
/**
* Gets the prefix of the root logger.
*/
public static String getRootLoggerPrefix() {
return rootLoggerPrefix;
}
public static String getTopicWithoutPrefix(String topic) {
if (classLoaderIsoltion && rootLoggerPrefix != null
&& topic.startsWith(rootLoggerPrefix)) {
return topic.substring(rootLoggerPrefix.length());
} else {
return topic;
}
}
/**
* isolates the logger hierarchy for a given class loader
* by prepending the root logger name.
*
* @param name user defined name
* @return internal name
*/
protected static String monoLoggerName(String name) {
if (!classLoaderIsoltion || name.startsWith(rootLoggerPrefix)) {
if (debug) {
debug("name already prefixed: " + name);
}
return name;
}
return rootLoggerPrefix + name;
}
/**
* Inidicates if the monolog wrapper must be logged itself.
*/
public static boolean debug = false;
static {
debug = new Boolean(System.getProperty("monolog.debug")).booleanValue();
classLoaderIsoltion = Boolean.valueOf(
System.getProperty(CLASSLOADER_ISOLATION, "true")).booleanValue();
}
/**
* This method must be only used to debug the Monolog wrappers.
* To active the log of monolog assign the "true" value to the system
* property "monolog.debug".
*
* @param m the message to log.
*/
public static void debug(String m) {
if (debug) {
System.out.println(m);
}
}
public static void warn(String m) {
System.err.println("WARN: " + m);
}
/**
* The default resource bundle of this factory
*/
protected String resourceBundleName = null;
/**
* This field references the level instances by their names.<br/>
* key = a level name<br/>
* value = the unique Level instance linked to the name.
*/
protected Map nameToLevel = null;
/**
* This field reference the level names by their integer value.<br/>
* key = a java.lang.Integer which the value is the level<br/>
* value = a String or an ArrayList of String. The strings represent the
* name which match to the integer value. Indeed both name can be associated
* to the same integer value.
*/
protected Map intToNames = null;
/**
* This field references the handler instance by their names.<br/>
* key = a String object which is an handler name.
* value = the unique handler instance which has the key for name.
*/
protected Map handlers = null;
/**
* This field references the MonolgFactoryListener instance by their names.<br/>
* key = a String object which is an handler name.
* value = the unique handler instance which has the key for name.
*/
protected Collection monologFactoryListeners = null;
/**
* It initializes the default monolog level: INHERIT, DEBUG, INFO, WARN,
* ERROR, FATAL
*/
public AbstractFactory() {
intToNames = new HashMap();
nameToLevel = new HashMap();
handlers = new HashMap();
monologFactoryListeners = new HashSet();
defineLevel(BasicLevel.LEVEL_INHERIT);
defineLevel(BasicLevel.LEVEL_DEBUG);
defineLevel(BasicLevel.LEVEL_INFO);
defineLevel(BasicLevel.LEVEL_WARN);
defineLevel(BasicLevel.LEVEL_ERROR);
defineLevel(BasicLevel.LEVEL_FATAL);
if (handlerType2className == null) {
synchronized(getClass()) {
if (handlerType2className == null) {
initHandlerType2className();
}
}
}
}
public abstract String getWrapperName();
protected void initHandlerType2className() {
handlerType2className = getDefaultHandlerType2className();
for(int i=0; i<handlerType2className.length; i++) {
handlerTypes[i] = handlerType2className[i][0];
}
String hts = System.getProperty("monolog." + getWrapperName() + ".handlerTypes");
if (hts != null && hts.length() > 0) {
StringTokenizer st = new StringTokenizer(hts,",;:|.", false);
Map m = null;
if (st.hasMoreTokens()) {
m = new HashMap();
}
while(st.hasMoreTokens()) {
//Handler type
String ht = st.nextToken();
//Handler class name
String hcn = System.getProperty("monolog.handlerType." + ht);
if (hcn != null && hcn.length() > 0) {
m.put(ht, hcn);
} else {
debug("Handler type '" + ht + "' not well defined: " + hcn);
}
}
if (m != null && m.size() > 0) {
//Copy old type
String[] newHT = new String[handlerTypes.length + m.size()];
System.arraycopy(handlerTypes, 0, newHT, 0, handlerTypes.length);
String[][] newHT2CN = new String[handlerTypes.length + m.size()][];
System.arraycopy(handlerType2className, 0, newHT2CN, 0, handlerType2className.length);
//Add the new ones
int i = handlerTypes.length;
for(Iterator it = m.entrySet().iterator(); it.hasNext();) {
Map.Entry me = (Map.Entry) it.next();
handlerTypes[i] = (String) me.getKey();
handlerType2className[i][0] = handlerTypes[i];
handlerType2className[i][1] = (String) me.getValue();
}
handlerTypes = newHT;
handlerType2className = newHT2CN;
}
}
}
abstract protected String[][] getDefaultHandlerType2className();
/**
* Insert a level into the data structure.<br/>
* If the level name is already used with other integer value, the null
* value is returned.<br/>
* If the level name is already used with the same integer value, the level
* found in the data structure is returned.<br/>
*
* @param l the Level instance which must be inserted.
* @return the Level instance or a null value.
*/
private Level defineLevel(Level l) {
//System.out.println("def(" + l + ") begin");
String name = l.getName();
int value = l.getIntValue();
Level res = (Level) nameToLevel.get(name);
if (res != null) {
// The name is already defined.
return (res.getIntValue() == value ? res : null);
} else {
res = l;
nameToLevel.put(name, res);
Integer i = new Integer(value);
Object temp = intToNames.get(i);
if (temp != null) {
if (temp instanceof String) {
if (!((String) temp).equalsIgnoreCase(name)) {
// The int value has already another name
// Add the new name to the other
ArrayList al = new ArrayList(5);
al.add(temp);
al.add(name);
intToNames.put(i, al);
}
}
else if (temp instanceof ArrayList) {
// The int value has already several another name
ArrayList al = (ArrayList) temp;
if (!al.contains(name)) {
// Add the new name to the others
al.add(name);
}
}
}
else {
// The int value does not have any name
intToNames.put(i, name);
}
//Calling the listeners
Iterator iterator = monologFactoryListeners.iterator ();
while (iterator.hasNext ()) {
MonologFactoryListener mfl = ((MonologFactoryListener)iterator.next ());
mfl.levelCreated (res);
}
}
//System.out.println("def(" + l + ") end");
return res;
}
// IMPLEMENTATION OF THE Configurable INTERFACE //
//----------------------------------------------//
public abstract void configure(Properties prop) throws Exception;
// IMPLEMENTATION OF INTERFACE LoggerFactory //
//-------------------------------------------//
public abstract Logger getLogger(String key);
public abstract Logger[] getLoggers();
public String getTopicPrefix() {
return rootLoggerPrefix;
}
public String getResourceBundleName() {
return resourceBundleName;
}
public void setResourceBundleName(String rbn) {
resourceBundleName = rbn;
}
// IMPLEMENTATION OF THE HandlerFactory INTERFACE //
//------------------------------------------------//
public Handler createHandler(String hn, String handlertype) {
Handler res = (Handler) handlers.get(hn);
if (res != null) {
return res;
}
if (handlertype == null) {
return null;
}
int i =0;
for(;i<handlerType2className.length
&& !handlerType2className[i][0].equalsIgnoreCase(handlertype); i++);
String handlerClassName;
if (i<handlerType2className.length) {
handlerClassName = handlerType2className[i][1];
} else {
handlerClassName = handlertype;
}
debug("Instanciating the handler '" + hn + "', class name=" + handlerClassName);
try {
res = (Handler) Class.forName(handlerClassName).newInstance();
} catch (Throwable e) {
warn("Impossible to instanciate the handler: name=" + hn
+ ", class name=" + handlerClassName +": " + e.getMessage());
e.printStackTrace(System.err);
return null;
}
res.setAttribute("handlertype", handlertype);
res.setName(hn);
handlers.put(hn, res);
//Calling the listeners
Iterator iterator = monologFactoryListeners.iterator ();
while (iterator.hasNext ()) {
MonologFactoryListener mfl = ((MonologFactoryListener)iterator.next ());
mfl.handlerCreated(res);
}
return res;
}
public Handler[] getHandlers() {
return (Handler[]) handlers.values().toArray(new Handler[0]);
}
public Handler getHandler(String hn) {
return (Handler) handlers.get(hn);
}
public Handler removeHandler(String hn) {
Handler res = (Handler) handlers.remove(hn);
if (res != null) {
//Calling the listeners
Iterator iterator = monologFactoryListeners.iterator ();
while (iterator.hasNext ()) {
MonologFactoryListener mfl = ((MonologFactoryListener)iterator.next ());
mfl.handlerRemoved(getHandler(hn));
}
}
return res;
}
// IMPLEMENTATION OF THE LevelFactory INTERFACE //
//-----------------------------------------------//
public Level defineLevel(String name, int value) {
return defineLevel(new LevelImpl(name, value));
}
public Level defineLevel(String name, String value) {
return defineLevel(new LevelImpl(name, value, this));
}
public Level getLevel(String name) {
return (Level) nameToLevel.get(name);
}
public Level getLevel(int value) {
Object temp = intToNames.get(new Integer(value));
if (temp == null) {
return null;
}
else if (temp instanceof String) {
return getLevel((String) temp);
}
else if (temp instanceof ArrayList) {
return getLevel((String) ((ArrayList) temp).get(0));
}
return null;
}
public Level[] getLevels() {
return (Level[]) nameToLevel.values().toArray(new Level[0]);
}
public void removeLevel(String name) {
Level removed = (Level) nameToLevel.remove(name);
if (removed != null) {
Integer i = new Integer(removed.getIntValue());
Object temp = intToNames.get(i);
if (temp instanceof String) {
intToNames.remove(i);
} else if (temp instanceof ArrayList) {
((ArrayList) temp).remove(name);
}
//Calling the listeners
Iterator iterator = monologFactoryListeners.iterator ();
while (iterator.hasNext ()) {
MonologFactoryListener mfl = ((MonologFactoryListener)iterator.next ());
mfl.levelRemoved(removed);
}
}
}
// IMPLEMENTATION OF THE MonologFactoryListener INTERFACE //
//-----------------------------------------------//
public void addMonologFactoryListener (MonologFactoryListener mfl) {
monologFactoryListeners.add(mfl);
}
public void removeMonologFactoryListener (MonologFactoryListener mfl) {
monologFactoryListeners.remove(mfl);
}
}