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    }