001: /* ====================================================================
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1997-2003 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution,
020: * if any, must include the following acknowledgment:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowledgment may appear in the software
024: * itself, if and wherever such third-party acknowledgments
025: * normally appear.
026: *
027: * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
028: * must not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation. For more
052: * information on the Apache Software Foundation, please see
053: * <http://www.apache.org/>.
054: */
055: package org.apache.log;
056:
057: import org.apache.log.format.PatternFormatter;
058: import org.apache.log.output.io.StreamTarget;
059: import org.apache.log.util.DefaultErrorHandler;
060: import org.apache.log.util.LoggerListener;
061:
062: /**
063: * This class encapsulates a basic independent log hierarchy.
064: * The hierarchy is essentially a safe wrapper around root logger.
065: *
066: * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
067: * @author <a href="mailto:peter@apache.org">Peter Donald</a>
068: */
069: public class Hierarchy {
070: ///Format of default formatter
071: private static final String FORMAT = "%7.7{priority} %23.23{time:yyyy-MM-dd' 'HH:mm:ss.SSS} [%8.8{category}] (%{context}): "
072: + "%{message}\n%{throwable}";
073:
074: ///The instance of default hierarchy
075: private static final Hierarchy HIERARCHY = new Hierarchy();
076:
077: ///Error Handler associated with hierarchy
078: private ErrorHandler m_errorHandler;
079:
080: ///The root logger which contains all Loggers in this hierarchy
081: private Logger m_rootLogger;
082:
083: ///LoggerListener associated with hierarchy
084: private LoggerListener m_loggerListener;
085:
086: /**
087: * Retrieve the default hierarchy.
088: *
089: * <p>In most cases the default LogHierarchy is the only
090: * one used in an application. However when security is
091: * a concern or multiple independent applications will
092: * be running in same JVM it is advantageous to create
093: * new Hierarchies rather than reuse default.</p>
094: *
095: * @return the default Hierarchy
096: */
097: public static Hierarchy getDefaultHierarchy() {
098: return HIERARCHY;
099: }
100:
101: /**
102: * Create a hierarchy object.
103: * The default LogTarget writes to stdout.
104: */
105: public Hierarchy() {
106: m_errorHandler = new DefaultErrorHandler();
107: m_rootLogger = new Logger(new InnerErrorHandler(),
108: new InnerLoggerListener(), "", null, null);
109:
110: //Setup default output target to print to console
111: final PatternFormatter formatter = new PatternFormatter(FORMAT);
112: final StreamTarget target = new StreamTarget(System.out,
113: formatter);
114:
115: setDefaultLogTarget(target);
116: }
117:
118: /**
119: * Set the default log target for hierarchy.
120: * This is the target inherited by loggers if no other target is specified.
121: *
122: * @param target the default target
123: */
124: public void setDefaultLogTarget(final LogTarget target) {
125: if (null == target) {
126: throw new IllegalArgumentException(
127: "Can not set DefaultLogTarget to null");
128: }
129:
130: final LogTarget[] targets = new LogTarget[] { target };
131: getRootLogger().setLogTargets(targets);
132: }
133:
134: /**
135: * Set the default log targets for this hierarchy.
136: * These are the targets inherited by loggers if no other targets are specified
137: *
138: * @param targets the default targets
139: */
140: public void setDefaultLogTargets(final LogTarget[] targets) {
141: if (null == targets || 0 == targets.length) {
142: throw new IllegalArgumentException(
143: "Can not set DefaultLogTargets to null");
144: }
145:
146: for (int i = 0; i < targets.length; i++) {
147: if (null == targets[i]) {
148: final String message = "Can not set DefaultLogTarget element to null";
149: throw new IllegalArgumentException(message);
150: }
151: }
152:
153: getRootLogger().setLogTargets(targets);
154: }
155:
156: /**
157: * Set the default priority for hierarchy.
158: * This is the priority inherited by loggers if no other priority is specified.
159: *
160: * @param priority the default priority
161: */
162: public void setDefaultPriority(final Priority priority) {
163: if (null == priority) {
164: final String message = "Can not set default Hierarchy Priority to null";
165: throw new IllegalArgumentException(message);
166: }
167:
168: getRootLogger().setPriority(priority);
169: }
170:
171: /**
172: * Set the ErrorHandler associated with hierarchy.
173: *
174: * @param errorHandler the ErrorHandler
175: */
176: public void setErrorHandler(final ErrorHandler errorHandler) {
177: if (null == errorHandler) {
178: final String message = "Can not set default Hierarchy ErrorHandler to null";
179: throw new IllegalArgumentException(message);
180: }
181:
182: m_errorHandler = errorHandler;
183: }
184:
185: /**
186: * Set the LoggerListener associated with hierarchy. This is a
187: * unicast listener, so only one LoggerListener is allowed.
188: *
189: * @param loggerListener the LoggerListener
190: *
191: * @throws UnsupportedOperationException if no more LoggerListeners are
192: * permitted.
193: */
194: public synchronized void addLoggerListener(
195: final LoggerListener loggerListener) {
196: if (null == loggerListener)
197: throw new NullPointerException("loggerListener");
198:
199: if (null == m_loggerListener) {
200: m_loggerListener = loggerListener;
201: } else {
202: throw new UnsupportedOperationException(
203: "LoggerListener already set on a unicast event notifier");
204: }
205: }
206:
207: /**
208: * Remove the LoggerListener associated with hierarchy. Perform this
209: * step before adding a new one if you want to change it.
210: *
211: * @param loggerListener the LoggerListener
212: */
213: public synchronized void removeLoggerListener(
214: final LoggerListener loggerListener) {
215: if (null == loggerListener)
216: throw new NullPointerException("loggerListener");
217:
218: if (null != m_loggerListener
219: && m_loggerListener == loggerListener)
220: ;
221: {
222: m_loggerListener = null;
223: }
224: }
225:
226: /**
227: * Retrieve a logger for named category.
228: *
229: * @param category the context
230: * @return the Logger
231: */
232: public Logger getLoggerFor(final String category) {
233: return getRootLogger().getChildLogger(category);
234: }
235:
236: /**
237: * Logs an error message to error handler.
238: * Default Error Handler is stderr.
239: *
240: * @param message a message to log
241: * @param throwable a Throwable to log
242: * @deprecated Logging components should use ErrorHandler rather than Hierarchy.log()
243: */
244: public void log(final String message, final Throwable throwable) {
245: m_errorHandler.error(message, throwable, null);
246: }
247:
248: /**
249: * Logs an error message to error handler.
250: * Default Error Handler is stderr.
251: *
252: * @param message a message to log
253: * @deprecated Logging components should use ErrorHandler rather than Hierarchy.log()
254: */
255: public void log(final String message) {
256: log(message, null);
257: }
258:
259: /**
260: * Notify logger listener (if any) that a new logger was created.
261: *
262: * @param category the category of new logger
263: * @param logger the logger
264: */
265: private synchronized void notifyLoggerCreated(
266: final String category, final Logger logger) {
267: if (null != m_loggerListener) {
268: m_loggerListener.loggerCreated(category, logger);
269: }
270: }
271:
272: /**
273: * Inner class to redirect to hierarchys real LoggerListener if any.
274: * Used so that all the loggers will not have to be updated
275: * when LoggerListener changes.
276: */
277: private class InnerLoggerListener extends LoggerListener {
278: /**
279: * Notify listener that a logger was created.
280: *
281: * @param category the category of logger
282: * @param logger the logger object
283: */
284: public void loggerCreated(final String category,
285: final Logger logger) {
286: notifyLoggerCreated(category, logger);
287: }
288: }
289:
290: private class InnerErrorHandler implements ErrorHandler {
291: /**
292: * Log an unrecoverable error.
293: *
294: * @param message the error message
295: * @param throwable the exception associated with error (may be null)
296: * @param event the LogEvent that caused error, if any (may be null)
297: */
298: public void error(final String message,
299: final Throwable throwable, final LogEvent event) {
300: m_errorHandler.error(message, throwable, event);
301: }
302: }
303:
304: /**
305: * Utility method to retrieve logger for hierarchy.
306: * This method is intended for use by sub-classes
307: * which can take responsibility for manipulating
308: * Logger directly.
309: *
310: * @return the Logger
311: */
312: public final Logger getRootLogger() {
313: return m_rootLogger;
314: }
315: }
|