001: /**
002: * Copyright (C) 2001-2003 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.util.monolog.wrapper.common;
018:
019: import org.objectweb.util.monolog.api.Logger;
020: import org.objectweb.util.monolog.api.Handler;
021: import org.objectweb.util.monolog.api.Level;
022: import org.objectweb.util.monolog.api.BasicLevel;
023: import org.objectweb.util.monolog.api.MonologFactory;
024: import org.objectweb.util.monolog.api.MonologFactoryListener;
025:
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.HashSet;
029: import java.util.Map;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Properties;
033: import java.util.StringTokenizer;
034:
035: /**
036: *
037: * @author S.Chassande-Barrioz
038: */
039: public abstract class AbstractFactory implements MonologFactory,
040: Configurable {
041:
042: public final static String CLASSLOADER_ISOLATION = "monolog.isolateclassloader";
043:
044: public static String[] handlerTypes = { "console", "file",
045: "rollingfile", "ntevent", "jmx" };
046:
047: public static String[][] handlerType2className = null;
048:
049: public static boolean classLoaderIsoltion = true;
050:
051: /**
052: * Root logger prefix, i.e. <code>rootLoggerName</code> followed by '.'.
053: */
054: protected static String rootLoggerPrefix = null;
055:
056: /**
057: * Name of the root logger.
058: * This name intends to isolates the loggers associated to a class loader.
059: */
060: protected static String rootLoggerName = null;
061:
062: /**
063: * Gets the prefix of the root logger.
064: */
065: public static String getRootLoggerPrefix() {
066: return rootLoggerPrefix;
067: }
068:
069: public static String getTopicWithoutPrefix(String topic) {
070: if (classLoaderIsoltion && rootLoggerPrefix != null
071: && topic.startsWith(rootLoggerPrefix)) {
072: return topic.substring(rootLoggerPrefix.length());
073: } else {
074: return topic;
075: }
076: }
077:
078: /**
079: * isolates the logger hierarchy for a given class loader
080: * by prepending the root logger name.
081: *
082: * @param name user defined name
083: * @return internal name
084: */
085: protected static String monoLoggerName(String name) {
086: if (!classLoaderIsoltion || name.startsWith(rootLoggerPrefix)) {
087: if (debug) {
088: debug("name already prefixed: " + name);
089: }
090: return name;
091: }
092: return rootLoggerPrefix + name;
093: }
094:
095: /**
096: * Inidicates if the monolog wrapper must be logged itself.
097: */
098: public static boolean debug = false;
099:
100: static {
101: debug = new Boolean(System.getProperty("monolog.debug"))
102: .booleanValue();
103: classLoaderIsoltion = Boolean.valueOf(
104: System.getProperty(CLASSLOADER_ISOLATION, "true"))
105: .booleanValue();
106: }
107:
108: /**
109: * This method must be only used to debug the Monolog wrappers.
110: * To active the log of monolog assign the "true" value to the system
111: * property "monolog.debug".
112: *
113: * @param m the message to log.
114: */
115: public static void debug(String m) {
116: if (debug) {
117: System.out.println(m);
118: }
119: }
120:
121: public static void warn(String m) {
122: System.err.println("WARN: " + m);
123: }
124:
125: /**
126: * The default resource bundle of this factory
127: */
128: protected String resourceBundleName = null;
129:
130: /**
131: * This field references the level instances by their names.<br/>
132: * key = a level name<br/>
133: * value = the unique Level instance linked to the name.
134: */
135: protected Map nameToLevel = null;
136:
137: /**
138: * This field reference the level names by their integer value.<br/>
139: * key = a java.lang.Integer which the value is the level<br/>
140: * value = a String or an ArrayList of String. The strings represent the
141: * name which match to the integer value. Indeed both name can be associated
142: * to the same integer value.
143: */
144: protected Map intToNames = null;
145:
146: /**
147: * This field references the handler instance by their names.<br/>
148: * key = a String object which is an handler name.
149: * value = the unique handler instance which has the key for name.
150: */
151: protected Map handlers = null;
152:
153: /**
154: * This field references the MonolgFactoryListener instance by their names.<br/>
155: * key = a String object which is an handler name.
156: * value = the unique handler instance which has the key for name.
157: */
158: protected Collection monologFactoryListeners = null;
159:
160: /**
161: * It initializes the default monolog level: INHERIT, DEBUG, INFO, WARN,
162: * ERROR, FATAL
163: */
164: public AbstractFactory() {
165: intToNames = new HashMap();
166: nameToLevel = new HashMap();
167: handlers = new HashMap();
168: monologFactoryListeners = new HashSet();
169: defineLevel(BasicLevel.LEVEL_INHERIT);
170: defineLevel(BasicLevel.LEVEL_DEBUG);
171: defineLevel(BasicLevel.LEVEL_INFO);
172: defineLevel(BasicLevel.LEVEL_WARN);
173: defineLevel(BasicLevel.LEVEL_ERROR);
174: defineLevel(BasicLevel.LEVEL_FATAL);
175: if (handlerType2className == null) {
176: synchronized (getClass()) {
177: if (handlerType2className == null) {
178: initHandlerType2className();
179: }
180: }
181: }
182: }
183:
184: public abstract String getWrapperName();
185:
186: protected void initHandlerType2className() {
187: handlerType2className = getDefaultHandlerType2className();
188: for (int i = 0; i < handlerType2className.length; i++) {
189: handlerTypes[i] = handlerType2className[i][0];
190: }
191:
192: String hts = System.getProperty("monolog." + getWrapperName()
193: + ".handlerTypes");
194: if (hts != null && hts.length() > 0) {
195: StringTokenizer st = new StringTokenizer(hts, ",;:|.",
196: false);
197: Map m = null;
198: if (st.hasMoreTokens()) {
199: m = new HashMap();
200: }
201: while (st.hasMoreTokens()) {
202: //Handler type
203: String ht = st.nextToken();
204: //Handler class name
205: String hcn = System.getProperty("monolog.handlerType."
206: + ht);
207: if (hcn != null && hcn.length() > 0) {
208: m.put(ht, hcn);
209: } else {
210: debug("Handler type '" + ht
211: + "' not well defined: " + hcn);
212: }
213: }
214: if (m != null && m.size() > 0) {
215: //Copy old type
216: String[] newHT = new String[handlerTypes.length
217: + m.size()];
218: System.arraycopy(handlerTypes, 0, newHT, 0,
219: handlerTypes.length);
220: String[][] newHT2CN = new String[handlerTypes.length
221: + m.size()][];
222: System.arraycopy(handlerType2className, 0, newHT2CN, 0,
223: handlerType2className.length);
224:
225: //Add the new ones
226: int i = handlerTypes.length;
227: for (Iterator it = m.entrySet().iterator(); it
228: .hasNext();) {
229: Map.Entry me = (Map.Entry) it.next();
230: handlerTypes[i] = (String) me.getKey();
231: handlerType2className[i][0] = handlerTypes[i];
232: handlerType2className[i][1] = (String) me
233: .getValue();
234: }
235: handlerTypes = newHT;
236: handlerType2className = newHT2CN;
237: }
238: }
239: }
240:
241: abstract protected String[][] getDefaultHandlerType2className();
242:
243: /**
244: * Insert a level into the data structure.<br/>
245: * If the level name is already used with other integer value, the null
246: * value is returned.<br/>
247: * If the level name is already used with the same integer value, the level
248: * found in the data structure is returned.<br/>
249: *
250: * @param l the Level instance which must be inserted.
251: * @return the Level instance or a null value.
252: */
253: private Level defineLevel(Level l) {
254: //System.out.println("def(" + l + ") begin");
255: String name = l.getName();
256: int value = l.getIntValue();
257: Level res = (Level) nameToLevel.get(name);
258: if (res != null) {
259: // The name is already defined.
260: return (res.getIntValue() == value ? res : null);
261: } else {
262: res = l;
263: nameToLevel.put(name, res);
264: Integer i = new Integer(value);
265: Object temp = intToNames.get(i);
266: if (temp != null) {
267: if (temp instanceof String) {
268: if (!((String) temp).equalsIgnoreCase(name)) {
269: // The int value has already another name
270: // Add the new name to the other
271: ArrayList al = new ArrayList(5);
272: al.add(temp);
273: al.add(name);
274: intToNames.put(i, al);
275: }
276: } else if (temp instanceof ArrayList) {
277: // The int value has already several another name
278: ArrayList al = (ArrayList) temp;
279: if (!al.contains(name)) {
280: // Add the new name to the others
281: al.add(name);
282: }
283: }
284: } else {
285: // The int value does not have any name
286: intToNames.put(i, name);
287: }
288: //Calling the listeners
289: Iterator iterator = monologFactoryListeners.iterator();
290: while (iterator.hasNext()) {
291: MonologFactoryListener mfl = ((MonologFactoryListener) iterator
292: .next());
293: mfl.levelCreated(res);
294: }
295: }
296: //System.out.println("def(" + l + ") end");
297: return res;
298: }
299:
300: // IMPLEMENTATION OF THE Configurable INTERFACE //
301: //----------------------------------------------//
302:
303: public abstract void configure(Properties prop) throws Exception;
304:
305: // IMPLEMENTATION OF INTERFACE LoggerFactory //
306: //-------------------------------------------//
307:
308: public abstract Logger getLogger(String key);
309:
310: public abstract Logger[] getLoggers();
311:
312: public String getTopicPrefix() {
313: return rootLoggerPrefix;
314: }
315:
316: public String getResourceBundleName() {
317: return resourceBundleName;
318: }
319:
320: public void setResourceBundleName(String rbn) {
321: resourceBundleName = rbn;
322: }
323:
324: // IMPLEMENTATION OF THE HandlerFactory INTERFACE //
325: //------------------------------------------------//
326:
327: public Handler createHandler(String hn, String handlertype) {
328: Handler res = (Handler) handlers.get(hn);
329: if (res != null) {
330: return res;
331: }
332: if (handlertype == null) {
333: return null;
334: }
335: int i = 0;
336: for (; i < handlerType2className.length
337: && !handlerType2className[i][0]
338: .equalsIgnoreCase(handlertype); i++)
339: ;
340: String handlerClassName;
341: if (i < handlerType2className.length) {
342: handlerClassName = handlerType2className[i][1];
343: } else {
344: handlerClassName = handlertype;
345: }
346: debug("Instanciating the handler '" + hn + "', class name="
347: + handlerClassName);
348: try {
349: res = (Handler) Class.forName(handlerClassName)
350: .newInstance();
351: } catch (Throwable e) {
352: warn("Impossible to instanciate the handler: name=" + hn
353: + ", class name=" + handlerClassName + ": "
354: + e.getMessage());
355: e.printStackTrace(System.err);
356: return null;
357: }
358: res.setAttribute("handlertype", handlertype);
359: res.setName(hn);
360: handlers.put(hn, res);
361: //Calling the listeners
362: Iterator iterator = monologFactoryListeners.iterator();
363: while (iterator.hasNext()) {
364: MonologFactoryListener mfl = ((MonologFactoryListener) iterator
365: .next());
366: mfl.handlerCreated(res);
367: }
368: return res;
369: }
370:
371: public Handler[] getHandlers() {
372: return (Handler[]) handlers.values().toArray(new Handler[0]);
373: }
374:
375: public Handler getHandler(String hn) {
376: return (Handler) handlers.get(hn);
377: }
378:
379: public Handler removeHandler(String hn) {
380: Handler res = (Handler) handlers.remove(hn);
381: if (res != null) {
382: //Calling the listeners
383: Iterator iterator = monologFactoryListeners.iterator();
384: while (iterator.hasNext()) {
385: MonologFactoryListener mfl = ((MonologFactoryListener) iterator
386: .next());
387: mfl.handlerRemoved(getHandler(hn));
388: }
389: }
390: return res;
391: }
392:
393: // IMPLEMENTATION OF THE LevelFactory INTERFACE //
394: //-----------------------------------------------//
395:
396: public Level defineLevel(String name, int value) {
397: return defineLevel(new LevelImpl(name, value));
398: }
399:
400: public Level defineLevel(String name, String value) {
401: return defineLevel(new LevelImpl(name, value, this ));
402: }
403:
404: public Level getLevel(String name) {
405: return (Level) nameToLevel.get(name);
406: }
407:
408: public Level getLevel(int value) {
409: Object temp = intToNames.get(new Integer(value));
410: if (temp == null) {
411: return null;
412: } else if (temp instanceof String) {
413: return getLevel((String) temp);
414: } else if (temp instanceof ArrayList) {
415: return getLevel((String) ((ArrayList) temp).get(0));
416: }
417: return null;
418: }
419:
420: public Level[] getLevels() {
421: return (Level[]) nameToLevel.values().toArray(new Level[0]);
422: }
423:
424: public void removeLevel(String name) {
425: Level removed = (Level) nameToLevel.remove(name);
426: if (removed != null) {
427: Integer i = new Integer(removed.getIntValue());
428: Object temp = intToNames.get(i);
429: if (temp instanceof String) {
430: intToNames.remove(i);
431: } else if (temp instanceof ArrayList) {
432: ((ArrayList) temp).remove(name);
433: }
434: //Calling the listeners
435: Iterator iterator = monologFactoryListeners.iterator();
436: while (iterator.hasNext()) {
437: MonologFactoryListener mfl = ((MonologFactoryListener) iterator
438: .next());
439: mfl.levelRemoved(removed);
440: }
441: }
442: }
443:
444: // IMPLEMENTATION OF THE MonologFactoryListener INTERFACE //
445: //-----------------------------------------------//
446:
447: public void addMonologFactoryListener(MonologFactoryListener mfl) {
448: monologFactoryListeners.add(mfl);
449: }
450:
451: public void removeMonologFactoryListener(MonologFactoryListener mfl) {
452: monologFactoryListeners.remove(mfl);
453: }
454: }
|