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.4 2005/11/14 10:55:43 mungady 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            final LogTarget[] targets = new LogTarget[this.logTargets.length];
264            System.arraycopy(targets, 0, this.logTargets, 0, this.logTargets.length);
265            return targets;
266        }
267    
268        /**
269         * Replaces all log targets by the given target.
270         *
271         * @param target the new and only logtarget.
272         */
273        public synchronized void replaceTargets(final LogTarget target) {
274            if (target == null) {
275                throw new NullPointerException();
276            }
277            this.logTargets = new LogTarget[]{target};
278        }
279    
280        /**
281         * A convenience method for logging a 'debug' message.
282         *
283         * @param message the message.
284         */
285        public static void debug(final Object message) {
286            log(LogTarget.DEBUG, message);
287        }
288    
289        /**
290         * A convenience method for logging a 'debug' message.
291         *
292         * @param message the message.
293         * @param e       the exception.
294         */
295        public static void debug(final Object message, final Exception e) {
296            log(LogTarget.DEBUG, message, e);
297        }
298    
299        /**
300         * A convenience method for logging an 'info' message.
301         *
302         * @param message the message.
303         */
304        public static void info(final Object message) {
305            log(LogTarget.INFO, message);
306        }
307    
308        /**
309         * A convenience method for logging an 'info' message.
310         *
311         * @param message the message.
312         * @param e       the exception.
313         */
314        public static void info(final Object message, final Exception e) {
315            log(LogTarget.INFO, message, e);
316        }
317    
318        /**
319         * A convenience method for logging a 'warning' message.
320         *
321         * @param message the message.
322         */
323        public static void warn(final Object message) {
324            log(LogTarget.WARN, message);
325        }
326    
327        /**
328         * A convenience method for logging a 'warning' message.
329         *
330         * @param message the message.
331         * @param e       the exception.
332         */
333        public static void warn(final Object message, final Exception e) {
334            log(LogTarget.WARN, message, e);
335        }
336    
337        /**
338         * A convenience method for logging an 'error' message.
339         *
340         * @param message the message.
341         */
342        public static void error(final Object message) {
343            log(LogTarget.ERROR, message);
344        }
345    
346        /**
347         * A convenience method for logging an 'error' message.
348         *
349         * @param message the message.
350         * @param e       the exception.
351         */
352        public static void error(final Object message, final Exception e) {
353            log(LogTarget.ERROR, message, e);
354        }
355    
356        /**
357         * Logs a message to the main log stream.  All attached log targets will also
358         * receive this message. If the given log-level is higher than the given debug-level
359         * in the main config file, no logging will be done.
360         *
361         * @param level   log level of the message.
362         * @param message text to be logged.
363         */
364        protected void doLog(int level, final Object message) {
365            if (level > 3) {
366                level = 3;
367            }
368            if (level <= this.debuglevel) {
369                for (int i = 0; i < this.logTargets.length; i++) {
370                    final LogTarget t = this.logTargets[i];
371                    t.log(level, message);
372                }
373            }
374        }
375    
376        /**
377         * Logs a message to the main log stream.  All attached log targets will also
378         * receive this message. If the given log-level is higher than the given debug-level
379         * in the main config file, no logging will be done.
380         *
381         * @param level   log level of the message.
382         * @param message text to be logged.
383         */
384        public static void log(final int level, final Object message) {
385            getInstance().doLog(level, message);
386        }
387    
388        /**
389         * Logs a message to the main log stream. All attached logTargets will also
390         * receive this message. If the given log-level is higher than the given debug-level
391         * in the main config file, no logging will be done.
392         * <p/>
393         * The exception's stacktrace will be appended to the log-stream
394         *
395         * @param level   log level of the message.
396         * @param message text to be logged.
397         * @param e       the exception, which should be logged.
398         */
399        public static void log(final int level, final Object message, final Exception e) {
400            getInstance().doLog(level, message, e);
401        }
402    
403        /**
404         * Logs a message to the main log stream. All attached logTargets will also
405         * receive this message. If the given log-level is higher than the given debug-level
406         * in the main config file, no logging will be done.
407         * <p/>
408         * The exception's stacktrace will be appended to the log-stream
409         *
410         * @param level   log level of the message.
411         * @param message text to be logged.
412         * @param e       the exception, which should be logged.
413         */
414        protected void doLog(int level, final Object message, final Exception e) {
415            if (level > 3) {
416                level = 3;
417            }
418    
419            if (level <= this.debuglevel) {
420                for (int i = 0; i < this.logTargets.length; i++) {
421                    final LogTarget t = this.logTargets[i];
422                    t.log(level, message, e);
423                }
424            }
425        }
426    
427        /**
428         * Initializes the logging system. Implementors should
429         * override this method to supply their own log configuration.
430         */
431        public void init() {
432            // this method is intentionally empty.
433        }
434    
435        /**
436         * Returns true, if the log level allows debug messages to be
437         * printed.
438         *
439         * @return true, if messages with an log level of DEBUG are allowed.
440         */
441        public static boolean isDebugEnabled() {
442            return getInstance().getDebuglevel() <= LogTarget.DEBUG;
443        }
444    
445        /**
446         * Returns true, if the log level allows informational
447         * messages to be printed.
448         *
449         * @return true, if messages with an log level of INFO are allowed.
450         */
451        public static boolean isInfoEnabled() {
452            return getInstance().getDebuglevel() <= LogTarget.INFO;
453        }
454    
455        /**
456         * Returns true, if the log level allows warning messages to be
457         * printed.
458         *
459         * @return true, if messages with an log level of WARN are allowed.
460         */
461        public static boolean isWarningEnabled() {
462            return getInstance().getDebuglevel() <= LogTarget.WARN;
463        }
464    
465        /**
466         * Returns true, if the log level allows error messages to be
467         * printed.
468         *
469         * @return true, if messages with an log level of ERROR are allowed.
470         */
471        public static boolean isErrorEnabled() {
472            return getInstance().getDebuglevel() <= LogTarget.ERROR;
473        }
474    
475        /**
476         * Creates a log context.
477         * 
478         * @param context  the class (<code>null</code> not permitted).
479         * 
480         * @return A log context.
481         */
482        public static LogContext createContext(final Class context) {
483            return createContext(context.getName());
484        }
485    
486        /**
487         * Creates a log context.
488         * 
489         * @param context  the label for the context.
490         * 
491         * @return A log context.
492         */
493        public static LogContext createContext(final String context) {
494            return getInstance().internalCreateContext(context);
495        }
496    
497        /**
498         * Creates a log context.
499         * 
500         * @param context  the name of the logging context (a common prefix).
501         * 
502         * @return A log context.
503         */
504        protected LogContext internalCreateContext(final String context) {
505            synchronized (this) {
506                LogContext ctx = (LogContext) this.logContexts.get(context);
507                if (ctx == null) {
508                    ctx = new LogContext(context);
509                    this.logContexts.put(context, ctx);
510                }
511                return ctx;
512            }
513        }
514        
515    }