content: /* ========================================================================
   * JCommon : a free general purpose class library for the Java(tm) platform
   * ========================================================================
   *
   * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   * 
   * Project Info:  http://www.jfree.org/jcommon/index.html
   *
   * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
   * USA.  
   *
   * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
   * in the United States and other countries.]
   * 
   * --------
   * Log.java
   * --------
   * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
   *
   * Original Author:  Thomas Morgner (taquera@sherito.org);
   * Contributor(s):   David Gilbert (for Object Refinery Limited);
   *
   * $Id: Log.java,v 1.5 2006/06/08 17:42:20 taqua Exp $
   *
   * Changes
   * -------
   * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
   * 11-Jun-2003 : Removing LogTarget did not work. 
   * 
   */
  
  package org.jfree.util;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  
  /**
   * A simple logging facility. Create a class implementing the {@link org.jfree.util.LogTarget}
   * interface to use this feature.
   *
   * @author Thomas Morgner
   */
  public class Log {
  
      /**
       * A simple message class.
       */
      public static class SimpleMessage {
  
          /**
           * The message.
           */
          private String message;
  
          /**
           * The parameters.
           */
          private Object[] param;
  
          /**
           * Creates a new message.
           *
           * @param message the message text.
           * @param param1  parameter 1.
           */
          public SimpleMessage(final String message, final Object param1) {
              this.message = message;
              this.param = new Object[]{param1};
          }
  
          /**
           * Creates a new message.
           *
           * @param message the message text.
           * @param param1  parameter 1.
           * @param param2  parameter 2.
           */
          public SimpleMessage(final String message, final Object param1,
                               final Object param2) {
              this.message = message;
              this.param = new Object[]{param1, param2};
          }
  
          /**
           * Creates a new message.
           *
           * @param message the message text.
           * @param param1  parameter 1.
           * @param param2  parameter 2.
           * @param param3  parameter 3.
           */
          public SimpleMessage(final String message, final Object param1,
                               final Object param2, final Object param3) {
              this.message = message;
              this.param = new Object[]{param1, param2, param3};
          }
  
          /**
           * Creates a new message.
           *
           * @param message the message text.
           * @param param1  parameter 1.
           * @param param2  parameter 2.
           * @param param3  parameter 3.
           * @param param4  parameter 4.
           */
          public SimpleMessage(final String message, final Object param1,
                               final Object param2, final Object param3,
                               final Object param4) {
              this.message = message;
              this.param = new Object[]{param1, param2, param3, param4};
          }
  
          /**
           * Creates a new message.
           *
           * @param message the message text.
           * @param param   the parameters.
           */
          public SimpleMessage(final String message, final Object[] param) {
              this.message = message;
              this.param = param;
          }
  
          /**
           * Returns a string representation of the message (useful for debugging).
           *
           * @return the string.
           */
          public String toString() {
              final StringBuffer b = new StringBuffer();
              b.append(this.message);
              if (this.param != null) {
                  for (int i = 0; i < this.param.length; i++) {
                      b.append(this.param[i]);
                  }
              }
              return b.toString();
          }
      }
  
  
      /**
       * The logging threshold.
       */
      private int debuglevel;
  
      /**
       * Storage for the log targets.
       */
      private LogTarget[] logTargets;
  
      /** The log contexts. */
      private HashMap logContexts;
  
      /**
       * the singleton instance of the Log system.
       */
      private static Log singleton;
  
      /**
       * Creates a new Log instance. The Log is used to manage the log targets.
       */
      protected Log() {
          this.logContexts = new HashMap();
          this.logTargets = new LogTarget[0];
          this.debuglevel = 100;
      }
  
      /**
       * Returns the singleton Log instance. A new instance is created if necessary.
       *
       * @return the singleton instance.
       */
      public static synchronized Log getInstance() {
          if (singleton == null) {
              singleton = new Log();
          }
          return singleton;
      }
  
      /**
       * Redefines or clears the currently used log instance.
       *
       * @param log the new log instance or null, to return to the default implementation.
       */
      protected static synchronized void defineLog(final Log log) {
          singleton = log;
      }
  
      /**
       * Returns the currently defined debug level. The higher the level, the more details
       * are printed.
       *
       * @return the debug level.
       */
      public int getDebuglevel() {
          return this.debuglevel;
      }
  
      /**
       * Defines the debug level for the log system.
       *
       * @param debuglevel the new debug level
       * @see #getDebuglevel()
       */
      protected void setDebuglevel(final int debuglevel) {
          this.debuglevel = debuglevel;
      }
  
      /**
       * Adds a log target to this facility. Log targets get informed, via the LogTarget interface,
       * whenever a message is logged with this class.
       *
       * @param target the target.
       */
      public synchronized void addTarget(final LogTarget target) {
          if (target == null) {
              throw new NullPointerException();
          }
          final LogTarget[] data = new LogTarget[this.logTargets.length + 1];
          System.arraycopy(this.logTargets, 0, data, 0, this.logTargets.length);
          data[this.logTargets.length] = target;
          this.logTargets = data;
      }
  
      /**
       * Removes a log target from this facility.
       *
       * @param target the target to remove.
       */
      public synchronized void removeTarget(final LogTarget target) {
          if (target == null) {
              throw new NullPointerException();
          }
          final ArrayList l = new ArrayList();
          l.addAll(Arrays.asList(this.logTargets));
          l.remove(target);
  
          final LogTarget[] targets = new LogTarget[l.size()];
          this.logTargets = (LogTarget[]) l.toArray(targets);
      }
  
      /**
       * Returns the registered logtargets.
       *
       * @return the logtargets.
       */
      public LogTarget[] getTargets() {
          return (LogTarget[]) this.logTargets.clone();
      }
  
      /**
       * Replaces all log targets by the given target.
       *
       * @param target the new and only logtarget.
       */
      public synchronized void replaceTargets(final LogTarget target) {
          if (target == null) {
              throw new NullPointerException();
          }
          this.logTargets = new LogTarget[]{target};
      }
  
      /**
       * A convenience method for logging a 'debug' message.
       *
       * @param message the message.
       */
      public static void debug(final Object message) {
          log(LogTarget.DEBUG, message);
      }
  
      /**
       * A convenience method for logging a 'debug' message.
       *
       * @param message the message.
       * @param e       the exception.
       */
      public static void debug(final Object message, final Exception e) {
          log(LogTarget.DEBUG, message, e);
      }
  
      /**
       * A convenience method for logging an 'info' message.
       *
       * @param message the message.
       */
      public static void info(final Object message) {
          log(LogTarget.INFO, message);
      }
  
      /**
       * A convenience method for logging an 'info' message.
       *
       * @param message the message.
       * @param e       the exception.
       */
      public static void info(final Object message, final Exception e) {
          log(LogTarget.INFO, message, e);
      }
  
      /**
       * A convenience method for logging a 'warning' message.
       *
       * @param message the message.
       */
      public static void warn(final Object message) {
          log(LogTarget.WARN, message);
      }
  
      /**
       * A convenience method for logging a 'warning' message.
       *
       * @param message the message.
       * @param e       the exception.
       */
      public static void warn(final Object message, final Exception e) {
          log(LogTarget.WARN, message, e);
      }
  
      /**
       * A convenience method for logging an 'error' message.
       *
       * @param message the message.
       */
      public static void error(final Object message) {
          log(LogTarget.ERROR, message);
      }
  
      /**
       * A convenience method for logging an 'error' message.
       *
       * @param message the message.
       * @param e       the exception.
       */
      public static void error(final Object message, final Exception e) {
          log(LogTarget.ERROR, message, e);
      }
  
      /**
       * Logs a message to the main log stream.  All attached log targets will also
       * receive this message. If the given log-level is higher than the given debug-level
       * in the main config file, no logging will be done.
       *
       * @param level   log level of the message.
       * @param message text to be logged.
       */
      protected void doLog(int level, final Object message) {
          if (level > 3) {
              level = 3;
          }
          if (level <= this.debuglevel) {
              for (int i = 0; i < this.logTargets.length; i++) {
                  final LogTarget t = this.logTargets[i];
                  t.log(level, message);
              }
          }
      }
  
      /**
       * Logs a message to the main log stream.  All attached log targets will also
       * receive this message. If the given log-level is higher than the given debug-level
       * in the main config file, no logging will be done.
       *
       * @param level   log level of the message.
       * @param message text to be logged.
       */
      public static void log(final int level, final Object message) {
          getInstance().doLog(level, message);
      }
  
      /**
       * Logs a message to the main log stream. All attached logTargets will also
       * receive this message. If the given log-level is higher than the given debug-level
       * in the main config file, no logging will be done.
       * <p/>
       * The exception's stacktrace will be appended to the log-stream
       *
       * @param level   log level of the message.
       * @param message text to be logged.
       * @param e       the exception, which should be logged.
       */
      public static void log(final int level, final Object message, final Exception e) {
          getInstance().doLog(level, message, e);
      }
  
      /**
       * Logs a message to the main log stream. All attached logTargets will also
       * receive this message. If the given log-level is higher than the given debug-level
       * in the main config file, no logging will be done.
       * <p/>
       * The exception's stacktrace will be appended to the log-stream
       *
       * @param level   log level of the message.
       * @param message text to be logged.
       * @param e       the exception, which should be logged.
       */
      protected void doLog(int level, final Object message, final Exception e) {
          if (level > 3) {
              level = 3;
          }
  
          if (level <= this.debuglevel) {
              for (int i = 0; i < this.logTargets.length; i++) {
                  final LogTarget t = this.logTargets[i];
                  t.log(level, message, e);
              }
          }
      }
  
      /**
       * Initializes the logging system. Implementors should
       * override this method to supply their own log configuration.
       */
      public void init() {
          // this method is intentionally empty.
      }
  
      /**
       * Returns true, if the log level allows debug messages to be
       * printed.
       *
       * @return true, if messages with an log level of DEBUG are allowed.
       */
      public static boolean isDebugEnabled() {
          return getInstance().getDebuglevel() >= LogTarget.DEBUG;
      }
  
      /**
       * Returns true, if the log level allows informational
       * messages to be printed.
       *
       * @return true, if messages with an log level of INFO are allowed.
       */
      public static boolean isInfoEnabled() {
          return getInstance().getDebuglevel() >= LogTarget.INFO;
      }
  
      /**
       * Returns true, if the log level allows warning messages to be
       * printed.
       *
       * @return true, if messages with an log level of WARN are allowed.
       */
      public static boolean isWarningEnabled() {
          return getInstance().getDebuglevel() >= LogTarget.WARN;
      }
  
      /**
       * Returns true, if the log level allows error messages to be
       * printed.
       *
       * @return true, if messages with an log level of ERROR are allowed.
       */
      public static boolean isErrorEnabled() {
          return getInstance().getDebuglevel() >= LogTarget.ERROR;
      }
  
      /**
       * Creates a log context.
       * 
       * @param context  the class (<code>null</code> not permitted).
       * 
       * @return A log context.
       */
      public static LogContext createContext(final Class context) {
          return createContext(context.getName());
      }
  
      /**
       * Creates a log context.
       * 
       * @param context  the label for the context.
       * 
       * @return A log context.
       */
      public static LogContext createContext(final String context) {
          return getInstance().internalCreateContext(context);
      }
  
      /**
       * Creates a log context.
       * 
       * @param context  the name of the logging context (a common prefix).
       * 
       * @return A log context.
       */
      protected LogContext internalCreateContext(final String context) {
          synchronized (this) {
              LogContext ctx = (LogContext) this.logContexts.get(context);
              if (ctx == null) {
                  ctx = new LogContext(context);
                  this.logContexts.put(context, ctx);
              }
              return ctx;
          }
      }
      
  }
  