001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package mx4j.log;
010:
011: import java.security.AccessController;
012: import java.security.PrivilegedAction;
013: import java.util.HashMap;
014: import java.util.Map;
015: import javax.management.RuntimeOperationsException;
016:
017: import mx4j.MX4JSystemKeys;
018:
019: /**
020: * Main class for the log service. <p>
021: * The system property 'mx4j.log.priority' controls the priority of the standard logging, and defaults to 'warn'.
022: * Possible values are, from least to greatest priority, the following (case insensitive):
023: * <ul>
024: * <li>trace
025: * <li>debug
026: * <li>info
027: * <li>warn
028: * <li>error
029: * <li>fatal
030: * </ul>
031: *
032: * @version $Revision: 1.7 $
033: */
034: public class Log {
035: private static Logger m_prototype;
036: private static Map m_prototypeMap = new HashMap();
037: private static Map m_loggerCache = new HashMap();
038: private static int m_defaultPriority;
039:
040: static {
041: // Do not require callers up in the stack to have this permission
042: String priority = (String) AccessController
043: .doPrivileged(new PrivilegedAction() {
044: public Object run() {
045: return System
046: .getProperty(MX4JSystemKeys.MX4J_LOG_PRIORITY);
047: }
048: });
049: if ("trace".equalsIgnoreCase(priority)) {
050: m_defaultPriority = Logger.TRACE;
051: } else if ("debug".equalsIgnoreCase(priority)) {
052: m_defaultPriority = Logger.DEBUG;
053: } else if ("info".equalsIgnoreCase(priority)) {
054: m_defaultPriority = Logger.INFO;
055: } else if ("warn".equalsIgnoreCase(priority)) {
056: m_defaultPriority = Logger.WARN;
057: } else if ("error".equalsIgnoreCase(priority)) {
058: m_defaultPriority = Logger.ERROR;
059: } else if ("fatal".equalsIgnoreCase(priority)) {
060: m_defaultPriority = Logger.FATAL;
061: } else {
062: m_defaultPriority = Logger.INFO;
063: }
064:
065: String prototype = (String) AccessController
066: .doPrivileged(new PrivilegedAction() {
067: public Object run() {
068: return System
069: .getProperty(MX4JSystemKeys.MX4J_LOG_PROTOTYPE);
070: }
071: });
072: if (prototype != null && prototype.trim().length() > 0) {
073: try {
074: ClassLoader cl = Thread.currentThread()
075: .getContextClassLoader();
076: Class cls = cl.loadClass(prototype);
077: redirectTo((Logger) cls.newInstance());
078: } catch (Exception x) {
079: x.printStackTrace();
080: // Do nothing else: the user will see the exception trace
081: // and understand that the property was wrong
082: }
083: }
084: }
085:
086: private Log() {
087: }
088:
089: /**
090: * Sets the default priority for all loggers.
091: *
092: * @see #setDefaultPriority
093: */
094: public static void setDefaultPriority(int priority) {
095: switch (priority) {
096: case Logger.TRACE:
097: m_defaultPriority = Logger.TRACE;
098: break;
099: case Logger.DEBUG:
100: m_defaultPriority = Logger.DEBUG;
101: break;
102: case Logger.INFO:
103: m_defaultPriority = Logger.INFO;
104: break;
105: case Logger.WARN:
106: m_defaultPriority = Logger.WARN;
107: break;
108: case Logger.ERROR:
109: m_defaultPriority = Logger.ERROR;
110: break;
111: case Logger.FATAL:
112: m_defaultPriority = Logger.FATAL;
113: break;
114: default:
115: m_defaultPriority = Logger.WARN;
116: break;
117: }
118: }
119:
120: /**
121: * Returns the default priority.
122: *
123: * @see #setDefaultPriority
124: */
125: public static int getDefaultPriority() {
126: return m_defaultPriority;
127: }
128:
129: /**
130: * Returns a new instance of a Logger associated with the given <code>category</code>;
131: * if {@link #redirectTo} has been called then a new instance of the prototype Logger, associated with the given
132: * <code>category<code>, is returned. This requires the prototype Logger class to have a public parameterless
133: * constructor.
134: */
135: public static Logger getLogger(String category) {
136: if (category == null) {
137: throw new RuntimeOperationsException(
138: new IllegalArgumentException(
139: "Category cannot be null"));
140: }
141:
142: synchronized (m_loggerCache) {
143: Logger logger = (Logger) m_loggerCache.get(category);
144: if (logger == null) {
145: // Try to see if a delegate for this category overrides other settings
146: Logger prototype = null;
147: synchronized (m_prototypeMap) {
148: prototype = (Logger) m_prototypeMap.get(category);
149: }
150: if (prototype == null) {
151: // Try to see if a prototype for all categories has been set
152: if (m_prototype != null) {
153: logger = createLogger(m_prototype, category);
154: } else {
155: logger = createLogger(null, category);
156: }
157: } else {
158: logger = createLogger(prototype, category);
159: }
160:
161: // cache it
162: m_loggerCache.put(category, logger);
163: }
164: return logger;
165: }
166: }
167:
168: private static Logger createLogger(Logger prototype, String category) {
169: Logger logger = null;
170: try {
171: logger = prototype == null ? new Logger()
172: : (Logger) prototype.getClass().newInstance();
173: } catch (Exception x) {
174: x.printStackTrace();
175: logger = new Logger();
176: }
177: logger.setCategory(category);
178: logger.setPriority(m_defaultPriority);
179: return logger;
180: }
181:
182: /**
183: * Tells to the log service to use the given <code>delegate</code> Logger to perform logging. <br>
184: * Use a null delegate to remove redirection.
185: *
186: * @see #getLogger
187: */
188: public static void redirectTo(Logger prototype) {
189: m_prototype = prototype;
190:
191: // Clear the cache, as we want requests for new loggers to be generated again.
192: synchronized (m_loggerCache) {
193: m_loggerCache.clear();
194: }
195: }
196:
197: /**
198: * Tells to the log service to use the given <code>delegate</code> Logger to perform logging for the given
199: * category (that cannot be null). <br>
200: * Settings made using this method overrides the ones made with {@link #redirectTo(Logger) redirectTo}, meaning
201: * that it is possible to redirect all the log to a certain delegate but certain categories.
202: * Use a null delegate to remove redirection for the specified category.
203: *
204: * @see #getLogger
205: */
206: public static void redirectTo(Logger prototype, String category) {
207: if (category == null) {
208: throw new RuntimeOperationsException(
209: new IllegalArgumentException(
210: "Category cannot be null"));
211: }
212:
213: if (prototype == null) {
214: // Remove the redirection
215: synchronized (m_prototypeMap) {
216: m_prototypeMap.remove(category);
217: }
218:
219: // Clear the cache for this category
220: synchronized (m_loggerCache) {
221: m_loggerCache.remove(category);
222: }
223: } else {
224: // Put or replace
225: synchronized (m_prototypeMap) {
226: m_prototypeMap.put(category, prototype);
227: }
228:
229: // Clear the cache for this category
230: synchronized (m_loggerCache) {
231: m_loggerCache.remove(category);
232: }
233: }
234: }
235: }
|