    001/* ========================================================================
    002 * JCommon : a free general purpose class library for the Java(tm) platform
    003 * ========================================================================
    004 *
    005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jcommon/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025 * in the United States and other countries.]
    026 *
    027 * --------
    028 * Log.java
    029 * --------
    030 * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
    031 *
    032 * Original Author:  Thomas Morgner (taquera@sherito.org);
    033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034 *
    035 * $Id: Log.java,v 1.5 2006/06/08 17:42:20 taqua Exp $
    036 *
    037 * Changes
    038 * -------
    039 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
    040 * 11-Jun-2003 : Removing LogTarget did not work.
    041 *
    042 */
    043
    044package org.jfree.util;
    045
    046import java.util.ArrayList;
    047import java.util.Arrays;
    048import java.util.HashMap;
    049
    050/**
    051 * A simple logging facility. Create a class implementing the {@link org.jfree.util.LogTarget}
    052 * interface to use this feature.
    053 *
    054 * @author Thomas Morgner
    055 */
    056public class Log {
    057
    058    /**
    059     * A simple message class.
    060     */
    061    public static class SimpleMessage {
    062
    063        /**
    064         * The message.
    065         */
    066        private String message;
    067
    068        /**
    069         * The parameters.
    070         */
    071        private Object[] param;
    072
    073        /**
    074         * Creates a new message.
    075         *
    076         * @param message the message text.
    077         * @param param1  parameter 1.
    078         */
    079        public SimpleMessage(final String message, final Object param1) {
    080            this.message = message;
    081            this.param = new Object[]{param1};
    082        }
    083
    084        /**
    085         * Creates a new message.
    086         *
    087         * @param message the message text.
    088         * @param param1  parameter 1.
    089         * @param param2  parameter 2.
    090         */
    091        public SimpleMessage(final String message, final Object param1,
    092                             final Object param2) {
    093            this.message = message;
    094            this.param = new Object[]{param1, param2};
    095        }
    096
    097        /**
    098         * Creates a new message.
    099         *
    100         * @param message the message text.
    101         * @param param1  parameter 1.
    102         * @param param2  parameter 2.
    103         * @param param3  parameter 3.
    104         */
    105        public SimpleMessage(final String message, final Object param1,
    106                             final Object param2, final Object param3) {
    107            this.message = message;
    108            this.param = new Object[]{param1, param2, param3};
    109        }
    110
    111        /**
    112         * Creates a new message.
    113         *
    114         * @param message the message text.
    115         * @param param1  parameter 1.
    116         * @param param2  parameter 2.
    117         * @param param3  parameter 3.
    118         * @param param4  parameter 4.
    119         */
    120        public SimpleMessage(final String message, final Object param1,
    121                             final Object param2, final Object param3,
    122                             final Object param4) {
    123            this.message = message;
    124            this.param = new Object[]{param1, param2, param3, param4};
    125        }
    126
    127        /**
    128         * Creates a new message.
    129         *
    130         * @param message the message text.
    131         * @param param   the parameters.
    132         */
    133        public SimpleMessage(final String message, final Object[] param) {
    134            this.message = message;
    135            this.param = param;
    136        }
    137
    138        /**
    139         * Returns a string representation of the message (useful for debugging).
    140         *
    141         * @return the string.
    142         */
    143        public String toString() {
    144            final StringBuffer b = new StringBuffer();
    145            b.append(this.message);
    146            if (this.param != null) {
    147                for (int i = 0; i < this.param.length; i++) {
    148                    b.append(this.param[i]);
    149                }
    150            }
    151            return b.toString();
    152        }
    153    }
    154
    155
    156    /**
    157     * The logging threshold.
    158     */
    159    private int debuglevel;
    160
    161    /**
    162     * Storage for the log targets.
    163     */
    164    private LogTarget[] logTargets;
    165
    166    /** The log contexts. */
    167    private HashMap logContexts;
    168
    169    /**
    170     * the singleton instance of the Log system.
    171     */
    172    private static Log singleton;
    173
    174    /**
    175     * Creates a new Log instance. The Log is used to manage the log targets.
    176     */
    177    protected Log() {
    178        this.logContexts = new HashMap();
    179        this.logTargets = new LogTarget[0];
    180        this.debuglevel = 100;
    181    }
    182
    183    /**
    184     * Returns the singleton Log instance. A new instance is created if necessary.
    185     *
    186     * @return the singleton instance.
    187     */
    188    public static synchronized Log getInstance() {
    189        if (singleton == null) {
    190            singleton = new Log();
    191        }
    192        return singleton;
    193    }
    194
    195    /**
    196     * Redefines or clears the currently used log instance.
    197     *
    198     * @param log the new log instance or null, to return to the default implementation.
    199     */
    200    protected static synchronized void defineLog(final Log log) {
    201        singleton = log;
    202    }
    203
    204    /**
    205     * Returns the currently defined debug level. The higher the level, the more details
    206     * are printed.
    207     *
    208     * @return the debug level.
    209     */
    210    public int getDebuglevel() {
    211        return this.debuglevel;
    212    }
    213
    214    /**
    215     * Defines the debug level for the log system.
    216     *
    217     * @param debuglevel the new debug level
    218     * @see #getDebuglevel()
    219     */
    220    protected void setDebuglevel(final int debuglevel) {
    221        this.debuglevel = debuglevel;
    222    }
    223
    224    /**
    225     * Adds a log target to this facility. Log targets get informed, via the LogTarget interface,
    226     * whenever a message is logged with this class.
    227     *
    228     * @param target the target.
    229     */
    230    public synchronized void addTarget(final LogTarget target) {
    231        if (target == null) {
    232            throw new NullPointerException();
    233        }
    234        final LogTarget[] data = new LogTarget[this.logTargets.length + 1];
    235        System.arraycopy(this.logTargets, 0, data, 0, this.logTargets.length);
    236        data[this.logTargets.length] = target;
    237        this.logTargets = data;
    238    }
    239
    240    /**
    241     * Removes a log target from this facility.
    242     *
    243     * @param target the target to remove.
    244     */
    245    public synchronized void removeTarget(final LogTarget target) {
    246        if (target == null) {
    247            throw new NullPointerException();
    248        }
    249        final ArrayList l = new ArrayList();
    250        l.addAll(Arrays.asList(this.logTargets));
    251        l.remove(target);
    252
    253        final LogTarget[] targets = new LogTarget[l.size()];
    254        this.logTargets = (LogTarget[]) l.toArray(targets);
    255    }
    256
    257    /**
    258     * Returns the registered logtargets.
    259     *
    260     * @return the logtargets.
    261     */
    262    public LogTarget[] getTargets() {
    263        return (LogTarget[]) this.logTargets.clone();
    264    }
    265
    266    /**
    267     * Replaces all log targets by the given target.
    268     *
    269     * @param target the new and only logtarget.
    270     */
    271    public synchronized void replaceTargets(final LogTarget target) {
    272        if (target == null) {
    273            throw new NullPointerException();
    274        }
    275        this.logTargets = new LogTarget[]{target};
    276    }
    277
    278    /**
    279     * A convenience method for logging a 'debug' message.
    280     *
    281     * @param message the message.
    282     */
    283    public static void debug(final Object message) {
    284        log(LogTarget.DEBUG, message);
    285    }
    286
    287    /**
    288     * A convenience method for logging a 'debug' message.
    289     *
    290     * @param message the message.
    291     * @param e       the exception.
    292     */
    293    public static void debug(final Object message, final Exception e) {
    294        log(LogTarget.DEBUG, message, e);
    295    }
    296
    297    /**
    298     * A convenience method for logging an 'info' message.
    299     *
    300     * @param message the message.
    301     */
    302    public static void info(final Object message) {
    303        log(LogTarget.INFO, message);
    304    }
    305
    306    /**
    307     * A convenience method for logging an 'info' message.
    308     *
    309     * @param message the message.
    310     * @param e       the exception.
    311     */
    312    public static void info(final Object message, final Exception e) {
    313        log(LogTarget.INFO, message, e);
    314    }
    315
    316    /**
    317     * A convenience method for logging a 'warning' message.
    318     *
    319     * @param message the message.
    320     */
    321    public static void warn(final Object message) {
    322        log(LogTarget.WARN, message);
    323    }
    324
    325    /**
    326     * A convenience method for logging a 'warning' message.
    327     *
    328     * @param message the message.
    329     * @param e       the exception.
    330     */
    331    public static void warn(final Object message, final Exception e) {
    332        log(LogTarget.WARN, message, e);
    333    }
    334
    335    /**
    336     * A convenience method for logging an 'error' message.
    337     *
    338     * @param message the message.
    339     */
    340    public static void error(final Object message) {
    341        log(LogTarget.ERROR, message);
    342    }
    343
    344    /**
    345     * A convenience method for logging an 'error' message.
    346     *
    347     * @param message the message.
    348     * @param e       the exception.
    349     */
    350    public static void error(final Object message, final Exception e) {
    351        log(LogTarget.ERROR, message, e);
    352    }
    353
    354    /**
    355     * Logs a message to the main log stream.  All attached log targets will also
    356     * receive this message. If the given log-level is higher than the given debug-level
    357     * in the main config file, no logging will be done.
    358     *
    359     * @param level   log level of the message.
    360     * @param message text to be logged.
    361     */
    362    protected void doLog(int level, final Object message) {
    363        if (level > 3) {
    364            level = 3;
    365        }
    366        if (level <= this.debuglevel) {
    367            for (int i = 0; i < this.logTargets.length; i++) {
    368                final LogTarget t = this.logTargets[i];
    369                t.log(level, message);
    370            }
    371        }
    372    }
    373
    374    /**
    375     * Logs a message to the main log stream.  All attached log targets will also
    376     * receive this message. If the given log-level is higher than the given debug-level
    377     * in the main config file, no logging will be done.
    378     *
    379     * @param level   log level of the message.
    380     * @param message text to be logged.
    381     */
    382    public static void log(final int level, final Object message) {
    383        getInstance().doLog(level, message);
    384    }
    385
    386    /**
    387     * Logs a message to the main log stream. All attached logTargets will also
    388     * receive this message. If the given log-level is higher than the given debug-level
    389     * in the main config file, no logging will be done.
    390     * <p/>
    391     * The exception's stacktrace will be appended to the log-stream
    392     *
    393     * @param level   log level of the message.
    394     * @param message text to be logged.
    395     * @param e       the exception, which should be logged.
    396     */
    397    public static void log(final int level, final Object message, final Exception e) {
    398        getInstance().doLog(level, message, e);
    399    }
    400
    401    /**
    402     * Logs a message to the main log stream. All attached logTargets will also
    403     * receive this message. If the given log-level is higher than the given debug-level
    404     * in the main config file, no logging will be done.
    405     * <p/>
    406     * The exception's stacktrace will be appended to the log-stream
    407     *
    408     * @param level   log level of the message.
    409     * @param message text to be logged.
    410     * @param e       the exception, which should be logged.
    411     */
    412    protected void doLog(int level, final Object message, final Exception e) {
    413        if (level > 3) {
    414            level = 3;
    415        }
    416
    417        if (level <= this.debuglevel) {
    418            for (int i = 0; i < this.logTargets.length; i++) {
    419                final LogTarget t = this.logTargets[i];
    420                t.log(level, message, e);
    421            }
    422        }
    423    }
    424
    425    /**
    426     * Initializes the logging system. Implementors should
    427     * override this method to supply their own log configuration.
    428     */
    429    public void init() {
    430        // this method is intentionally empty.
    431    }
    432
    433    /**
    434     * Returns true, if the log level allows debug messages to be
    435     * printed.
    436     *
    437     * @return true, if messages with an log level of DEBUG are allowed.
    438     */
    439    public static boolean isDebugEnabled() {
    440        return getInstance().getDebuglevel() >= LogTarget.DEBUG;
    441    }
    442
    443    /**
    444     * Returns true, if the log level allows informational
    445     * messages to be printed.
    446     *
    447     * @return true, if messages with an log level of INFO are allowed.
    448     */
    449    public static boolean isInfoEnabled() {
    450        return getInstance().getDebuglevel() >= LogTarget.INFO;
    451    }
    452
    453    /**
    454     * Returns true, if the log level allows warning messages to be
    455     * printed.
    456     *
    457     * @return true, if messages with an log level of WARN are allowed.
    458     */
    459    public static boolean isWarningEnabled() {
    460        return getInstance().getDebuglevel() >= LogTarget.WARN;
    461    }
    462
    463    /**
    464     * Returns true, if the log level allows error messages to be
    465     * printed.
    466     *
    467     * @return true, if messages with an log level of ERROR are allowed.
    468     */
    469    public static boolean isErrorEnabled() {
    470        return getInstance().getDebuglevel() >= LogTarget.ERROR;
    471    }
    472
    473    /**
    474     * Creates a log context.
    475     *
    476     * @param context  the class (<code>null</code> not permitted).
    477     *
    478     * @return A log context.
    479     */
    480    public static LogContext createContext(final Class context) {
    481        return createContext(context.getName());
    482    }
    483
    484    /**
    485     * Creates a log context.
    486     *
    487     * @param context  the label for the context.
    488     *
    489     * @return A log context.
    490     */
    491    public static LogContext createContext(final String context) {
    492        return getInstance().internalCreateContext(context);
    493    }
    494
    495    /**
    496     * Creates a log context.
    497     *
    498     * @param context  the name of the logging context (a common prefix).
    499     *
    500     * @return A log context.
    501     */
    502    protected LogContext internalCreateContext(final String context) {
    503        synchronized (this) {
    504            LogContext ctx = (LogContext) this.logContexts.get(context);
    505            if (ctx == null) {
    506                ctx = new LogContext(context);
    507                this.logContexts.put(context, ctx);
    508            }
    509            return ctx;
    510        }
    511    }
    512
    513}