    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
    044    package org.jfree.util;
    045
    046    import java.util.ArrayList;
    047    import java.util.Arrays;
    048    import 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     */
    056    public 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    }