diff src/com/go/trove/log/Log.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/go/trove/log/Log.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,561 @@
+/* ====================================================================
+ * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
+ * ====================================================================
+ * The Tea Software License, Version 1.1
+ *
+ * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Walt Disney Internet Group (http://opensource.go.com/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact opensource@dig.com.
+ *
+ * 5. Products derived from this software may not be called "Tea",
+ *    "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
+ *    "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
+ *    written permission of the Walt Disney Internet Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * For more information about Tea, please see http://opensource.go.com/.
+ */
+
+package com.go.trove.log;
+
+import java.io.*;
+import java.util.*;
+import java.lang.ref.WeakReference;
+
+/******************************************************************************
+ * General purpose logging class that operates using a hierarchy of Logs and
+ * an event model. All LogEvents are categorized into one of four types: 
+ * debugging, informational, warning and error.
+ *
+ * A log event can be generated by writing to one of the four PrintWriter
+ * fields provided (debug, info, warn and error), or by calling the debug,
+ * info, warn or error methods.
+ *
+ * Logs can have a parent Log, which by default, receives all the events
+ * that the Log generates or receives. If a log is disabled, it will not
+ * generate or propagate events.
+ *
+ * Examples:
+ * <pre>
+ * Log log = new Log("test", null);
+ * log.addLogListener(new LogScribe(new PrintWriter(System.out)));
+ *
+ * log.debug().println("Printing a debugging message");
+ * log.info("System running");
+ *
+ * Syslog.info().println("Creating child log...");
+ * Log child = new Log("child", Syslog.log);
+ * child.warn("This is a system warning...");
+ *
+ * try {
+ *     ...
+ * }
+ * catch (Exception e) {
+ *     child.error(e);
+ * }
+ *
+ * Log saved = new Log("saved", Syslog.log);
+ * File logDir = new File("/logs/");
+ * OutputStream out = new DailyFileLogStream(logDir);
+ * saved.addLogListener(new LogScribe(new PrintWriter(out)));
+ * saved.info("Saved log file initialized");
+ * </pre>
+ *
+ * @author Brian S O'Neill
+ * @version
+ * <!--$$Revision: 1.1 $-->, <!--$$JustDate:-->  6/28/01 <!-- $-->
+ * @see LogScribe
+ * @see Syslog
+ * @see LogEventParsingWriter
+ * @see DailyFileLogStream
+ */
+public class Log implements LogListener, Serializable {
+    private static final int ENABLED_MASK = 0x01;
+    private static final int DEBUG_ENABLED_MASK = 0x02;
+    private static final int INFO_ENABLED_MASK = 0x04;
+    private static final int WARN_ENABLED_MASK = 0x08;
+    private static final int ERROR_ENABLED_MASK = 0x10;
+
+    private final transient PrintWriter mDebug;
+    private final transient PrintWriter mInfo;
+    private final transient PrintWriter mWarn;
+    private final transient PrintWriter mError;
+
+    private Log mParent;
+    private Collection mChildren = new Vector();
+    private String mName;
+    private String mDescription;
+    private int mEnabledFlags = 0xfffffff;
+    private transient List mListeners = new Vector();
+
+    /**
+     * Create a new Log that inherits enabled settings from its parent. If no
+     * parent is specified, then the Log is fully enabled. If a parent is
+     * specified, then it is added automatically as a listener to this Log.
+     *
+     * @param name The optional name of this Log.
+     * @param parent The parent Log that will be added as a LogListener to this
+     * Log. If null, then this Log has no parent Log.
+     */
+    public Log(String name, Log parent) {
+        this();
+
+        if (parent != null) {
+            mParent = parent;
+            parent.mChildren.add(new WeakReference(this));
+            mEnabledFlags = parent.mEnabledFlags;
+            addLogListener(parent);
+        }
+
+        mName = name;
+        mDescription = name;
+    }
+
+    private Log() {
+        LogEventParsingWriter writer;
+
+        writer = new LogEventParsingWriter(this, LogEvent.DEBUG_TYPE, this) {
+            public boolean isEnabled() {
+                return isDebugEnabled();
+            }
+        };
+        writer.addLogListener(this);
+        mDebug = new PrintWriter(writer, true);
+
+        writer = new LogEventParsingWriter(this, LogEvent.INFO_TYPE, this) {
+            public boolean isEnabled() {
+                return isInfoEnabled();
+            }
+        };
+        writer.addLogListener(this);
+        mInfo = new PrintWriter(writer, true);
+
+        writer = new LogEventParsingWriter(this, LogEvent.WARN_TYPE, this) {
+            public boolean isEnabled() {
+                return isWarnEnabled();
+            }
+        };
+        writer.addLogListener(this);
+        mWarn = new PrintWriter(writer, true);
+
+        writer = new LogEventParsingWriter(this, LogEvent.ERROR_TYPE, this) {
+            public boolean isEnabled() {
+                return isErrorEnabled();
+            }
+        };
+        writer.addLogListener(this);
+        mError = new PrintWriter(writer, true);
+    }
+
+    /**
+     * adds a listener to the root log, the log with a null parent
+     */
+    public void addRootLogListener(LogListener listener) {
+        if (mParent == null) {
+            addLogListener(listener);
+        }
+        else {
+            mParent.addRootLogListener(listener);
+        }
+    }
+
+    public void removeRootLogListener(LogListener listener) {
+        mListeners.remove(listener);
+        if (mParent == null) {
+            removeLogListener(listener);
+        }
+        else {
+            mParent.removeRootLogListener(listener);
+        }
+    }
+
+    public void addLogListener(LogListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeLogListener(LogListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * If this Log is enabled, then dispatch the LogEvent to all of its
+     * listeners as a logged message.
+     */
+    public void logMessage(LogEvent e) {
+        if (isEnabled()) {
+            dispatchLogMessage(e);
+        }
+    }
+
+    /**
+     * If this Log is enabled, then dispatch the LogEvent to all of its
+     * listeners as a logged exception.
+     */
+    public void logException(LogEvent e) {
+        if (isEnabled()) {
+            dispatchLogException(e);
+        }
+    }
+
+    private void dispatchLogMessage(LogEvent e) {
+        int size = mListeners.size();
+        try {
+            for (int i=0; i<size; i++) {
+                ((LogListener)mListeners.get(i)).logMessage(e);
+            }
+        }
+        catch (IndexOutOfBoundsException ex) {
+        }
+    }
+
+    private void dispatchLogException(LogEvent e) {
+        int size = mListeners.size();
+        try {
+            for (int i=0; i<size; i++) {
+                ((LogListener)mListeners.get(i)).logException(e);
+            }
+        }
+        catch (IndexOutOfBoundsException ex) {
+        }
+    }
+
+    /**
+     * Returns a PrintWriter for debug messages.
+     */
+    public PrintWriter debug() {
+        return mDebug;
+    }
+
+    /**
+     * Simple method for logging a single debugging message.
+     */
+    public synchronized void debug(String s) {
+        if (isEnabled() && isDebugEnabled()) {
+            dispatchLogMessage(new LogEvent(this, LogEvent.DEBUG_TYPE, s));
+        }
+    }
+
+    /**
+     * Simple method for logging a single debugging exception.
+     */
+    public synchronized void debug(Throwable t) {
+        if (isEnabled() && isDebugEnabled()) {
+            dispatchLogException(new LogEvent(this, LogEvent.DEBUG_TYPE, t));
+        }
+    }
+
+    /**
+     * Returns a PrintWriter for information messages.
+     */
+    public PrintWriter info() {
+        return mInfo;
+    }
+
+    /**
+     * Simple method for logging a single information message.
+     */
+    public synchronized void info(String s) {
+        if (isEnabled() && isInfoEnabled()) {
+            dispatchLogMessage(new LogEvent(this, LogEvent.INFO_TYPE, s));
+        }
+    }
+
+    /**
+     * Simple method for logging a single information exception.
+     */
+    public synchronized void info(Throwable t) {
+        if (isEnabled() && isInfoEnabled()) {
+            dispatchLogException(new LogEvent(this, LogEvent.INFO_TYPE, t));
+        }
+    }
+
+    /**
+     * Returns a PrintWriter for warning messages.
+     */
+    public PrintWriter warn() {
+        return mWarn;
+    }
+
+    /**
+     * Simple method for logging a single warning message.
+     */
+    public synchronized void warn(String s) {
+        if (isEnabled() && isWarnEnabled()) {
+            dispatchLogMessage(new LogEvent(this, LogEvent.WARN_TYPE, s));
+        }
+    }
+
+    /**
+     * Simple method for logging a single warning exception.
+     */
+    public synchronized void warn(Throwable t) {
+        if (isEnabled() && isWarnEnabled()) {
+            dispatchLogException(new LogEvent(this, LogEvent.WARN_TYPE, t));
+        }
+    }
+
+    /**
+     * Returns a PrintWriter for error messages.
+     */
+    public PrintWriter error() {
+        return mError;
+    }
+
+    /**
+     * Simple method for logging a single error message.
+     */
+    public synchronized void error(String s) {
+        if (isEnabled() && isErrorEnabled()) {
+            dispatchLogMessage(new LogEvent(this, LogEvent.ERROR_TYPE, s));
+        }
+    }
+
+    /**
+     * Simple method for logging a single error exception.
+     */
+    public synchronized void error(Throwable t) {
+        if (isEnabled() && isErrorEnabled()) {
+            dispatchLogException(new LogEvent(this, LogEvent.ERROR_TYPE, t));
+        }
+    }
+
+    /**
+     * Returns a copy of the children Logs.
+     */
+    public Log[] getChildren() {
+        Collection copy;
+
+        synchronized (mChildren) {
+            copy = new ArrayList(mChildren.size());
+            Iterator it = mChildren.iterator();
+            while (it.hasNext()) {
+                Log child = (Log)((WeakReference)it.next()).get();
+                if (child == null) {
+                    it.remove();
+                }
+                else {
+                    copy.add(child);
+                }
+            }
+        }
+
+        return (Log[])copy.toArray(new Log[copy.size()]);
+    }
+
+    /**
+     * Returns null if this Log has no name.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns a brief description of this Log. By default, returns the name.
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * Set the log's description text.
+     */
+    public void setDescription(String desc) {
+        mDescription = desc;
+    }
+
+    /**
+     * Returns true if this Log is enabled. If log is disabled, then no log 
+     * events of any kind are generated or propagated to listeners.
+     */
+    public boolean isEnabled() {
+        return isEnabled(ENABLED_MASK);
+    }
+
+    /**
+     * When this Log is enabled, all parent Logs are also enabled. When this
+     * Log is disabled, parent Logs are unaffected.
+     */
+    public synchronized void setEnabled(boolean enabled) {
+        setEnabled(enabled, ENABLED_MASK);
+        if (enabled) {
+            Log parent;
+            if ((parent = mParent) != null) {
+                parent.setEnabled(true);
+            }
+        }
+    }
+
+    /**
+     * Returns true if debug events for this Log are enabled. If debug events
+     * are disabled, then no debug log events are generated, but they can be
+     * propagated to listeners.
+     */
+    public boolean isDebugEnabled() {
+        return isEnabled(DEBUG_ENABLED_MASK);
+    }
+
+    /**
+     * When debug is enabled, this Log is enabled and all parent Logs are
+     * enabled. Disabling debug only affects this Log's debug state.
+     */
+    public synchronized void setDebugEnabled(boolean enabled) {
+        setEnabled(enabled, DEBUG_ENABLED_MASK);
+        if (enabled) {
+            setEnabled(true);
+        }
+    }
+
+    /**
+     * Returns true if info events for this Log are enabled. If info events
+     * are disabled, then no info log events are generated, but they can be
+     * propagated to listeners.
+     */
+    public boolean isInfoEnabled() {
+        return isEnabled(INFO_ENABLED_MASK);
+    }
+
+    /**
+     * When info is enabled, this Log is enabled and all parent Logs are
+     * enabled. Disabling info only affects this Log's info state.
+     */
+    public synchronized void setInfoEnabled(boolean enabled) {
+        setEnabled(enabled, INFO_ENABLED_MASK);
+        if (enabled) {
+            setEnabled(true);
+        }
+    }
+
+    /**
+     * Returns true if warn events for this Log are enabled. If warn events
+     * are disabled, then no warn log events are generated, but they can be
+     * propagated to listeners.
+     */
+    public boolean isWarnEnabled() {
+        return isEnabled(WARN_ENABLED_MASK);
+    }
+
+    /**
+     * When warn is enabled, this Log is enabled and all parent Logs are
+     * enabled. Disabling warn only affects this Log's warn state.
+     */
+    public synchronized void setWarnEnabled(boolean enabled) {
+        setEnabled(enabled, WARN_ENABLED_MASK);
+        if (enabled) {
+            setEnabled(true);
+        }
+    }
+
+    /**
+     * Returns true if error events for this Log are enabled. If error events
+     * are disabled, then no error log events are generated, but they can be
+     * propagated to listeners.
+     */
+    public boolean isErrorEnabled() {
+        return isEnabled(ERROR_ENABLED_MASK);
+    }
+
+    /**
+     * When error is enabled, this Log is enabled and all parent Logs are
+     * enabled. Disabling error only affects this Log's error state.
+     */
+    public synchronized void setErrorEnabled(boolean enabled) {
+        setEnabled(enabled, ERROR_ENABLED_MASK);
+        if (enabled) {
+            setEnabled(true);
+        }
+    }
+
+    /**
+     * Understands and applies the following boolean properties. True is the
+     * default value if the value doesn't equal "false", ignoring case.
+     *
+     * <ul>
+     * <li>enabled
+     * <li>debug
+     * <li>info
+     * <li>warn
+     * <li>error
+     * </ul>
+     */
+    public synchronized void applyProperties(Map properties) {
+        if (properties.containsKey("enabled")) {
+            setEnabled(!"false".equalsIgnoreCase
+                       ((String)properties.get("enabled")));
+        }
+
+        if (properties.containsKey("debug")) {
+            setDebugEnabled(!"false".equalsIgnoreCase
+                            ((String)properties.get("debug")));
+        }
+
+        if (properties.containsKey("info")) {
+            setInfoEnabled(!"false".equalsIgnoreCase
+                           ((String)properties.get("info")));
+        }
+
+        if (properties.containsKey("warn")) {
+            setWarnEnabled(!"false".equalsIgnoreCase
+                           ((String)properties.get("warn")));
+        }
+
+        if (properties.containsKey("error")) {
+            setErrorEnabled(!"false".equalsIgnoreCase
+                            ((String)properties.get("error")));
+        }
+    }
+
+    /**
+     * Returns a short description of this log.
+     */
+    public String toString() {
+        return "Log[" + getDescription() + "]@" + 
+            Integer.toHexString(hashCode());
+    }
+
+    private synchronized boolean isEnabled(int mask) {
+        return (mEnabledFlags & mask) == mask;
+    }
+
+    private synchronized void setEnabled(boolean enabled, int mask) {
+        if (enabled) {
+            mEnabledFlags |= mask;
+        }
+        else {
+            mEnabledFlags &= ~mask;
+        }
+    }
+}