001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: Debug.java,v 1.6 2009/08/19 05:41:17 veiming Exp $
026 *
027 * Portions Copyrighted 2013 Forgerock AS.
028 *
029 */
030
031package com.sun.identity.shared.debug;
032
033import com.sun.identity.shared.configuration.SystemPropertiesManager;
034import com.sun.identity.shared.debug.impl.DebugProviderImpl;
035import java.util.Collection;
036import java.util.HashMap;
037import java.util.Map;
038import java.util.ResourceBundle;
039
040
041// NOTE: Since JVM specs guarantee atomic access/updates to int variables
042// (actually all variables except double and long), the design consciously
043// avoids synchronized methods, particularly for message(). This is done to
044// reduce the performance overhead of synchronized message() when debugging
045// is disabled. This does not have serious side-effects other than an occasional
046// invocation of message() missing concurrent update of 'debugLevel'.
047
048/*******************************************************************************
049 * <p>
050 * Allows a uniform interface to file debug and exception information in a
051 * uniform format. <code>Debug</code> supports different levels/states of
052 * filing debug information (in the ascending order): <code>OFF</code>,
053 * <code>ERROR</code>, <code>WARNING</code>, <code>MESSAGE</code> and
054 * <code>ON</code>. A given debug level/state is enabled if the debug
055 * state/level is set to at least that state/level. For example, if the debug
056 * state is <code>ERROR</code>, only errors will be filed. If the debug state
057 * is <code>WARNING</code>, only errors and warnings will be filed. If the
058 * debug state is <code>MESSAGE</code>, everything will be filed.
059 * <code>MESSAGE</code> and <code>ON</code> are of the same levels; the
060 * difference between them being <code>MESSAGE</code> writes to a file,
061 * whereas <code>ON</code> writes to System.out.
062 * </p>
063 * <p>
064 * Debug service uses the property file, <code>AMConfig.properties</code>, to
065 * set the default debug level and the output directory where the debug files
066 * will be placed. The properties file is located (using
067 * {@link java.util.ResourceBundle} semantics) from one of the directories in
068 * the CLASSPATH.
069 * </p>
070 * <p>
071 * The following keys are used to configure the Debug service. Possible values
072 * for the key 'com.iplanet.services.debug.level' are: off | error | warning |
073 * message. The key 'com.iplanet.services.debug.directory' specifies the output
074 * directory where the debug files will be created. Optionally, the key
075 * 'com.sun.identity.util.debug.provider' may be used to plugin a non-default
076 * implementation of the debug service where necessary.
077 * </p>
078 * 
079 * <blockquote>
080 * 
081 * <pre>
082 *  com.iplanet.services.debug.level
083 *  com.iplanet.services.debug.directory
084 *  com.sun.identity.util.debug.provider
085 * </pre>
086 * 
087 * </blockquote>
088 * 
089 * If there is an error reading or loading the properties, Debug service will
090 * redirect all debug information to <code>System.out</code>
091 * 
092 * If these properties are changed, the server must be restarted for the changes
093 * to take effect.
094 * 
095 * <p>
096 * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt application
097 * performance when abused. Particularly, note that Java evaluates the arguments
098 * to <code>message()</code> and <code>warning()</code> even when debugging
099 * is turned off. It is recommended that the debug state be checked before
100 * invoking any <code>message()</code> or <code>warning()</code> methods to
101 * avoid unnecessary argument evaluation and to maximize application
102 * performance.
103 * </p>
104 * @supported.all.api
105 */
106public class Debug {
107
108    /* Static fields and methods */
109
110    /** flags the disabled debug state. */
111    public static final int OFF = 0;
112
113    /**
114     * flags the state where error debugging is enabled. When debugging is set
115     * to less than <code>ERROR</code>, error debugging is also disabled.
116     */
117    public static final int ERROR = 1;
118
119    /**
120     * flags the state where warning debugging is enabled, but message debugging
121     * is disabled. When debugging is set to less than <code>WARNING</code>,
122     * warning debugging is also disabled.
123     */
124    public static final int WARNING = 2;
125
126    /** This state enables debugging of messages, warnings and errors. */
127    public static final int MESSAGE = 3;
128
129    /**
130     * flags the enabled debug state for warnings, errors and messages. Printing
131     * to a file is disabled. All printing is done on System.out.
132     */
133    public static final int ON = 4;
134
135    /** flags the disabled debug state. */
136    public static final String STR_OFF = "off";
137
138    /**
139     * flags the state where error debugging is enabled. When debugging is set
140     * to less than <code>ERROR</code>, error debugging is also disabled.
141     */
142    public static final String STR_ERROR = "error";
143
144    /**
145     * flags the state where warning debugging is enabled, but message debugging
146     * is disabled. When debugging is set to less than <code>WARNING</code>,
147     * warning debugging is also disabled.
148     */
149    public static final String STR_WARNING = "warning";
150
151    /** This state enables debugging of messages, warnings and errors. */
152    public static final String STR_MESSAGE = "message";
153
154    /**
155     * flags the enables debug state for warnings, errors and messages. Printing
156     * to a file is disabled. All printing is done on System.out.
157     */
158    public static final String STR_ON = "on";
159
160    /**
161     * debugMap is a container of all active Debug objects. Log file name is the
162     * key and Debug is the value of this map.
163     */
164    private static Map debugMap = new HashMap();
165
166    /**
167     * serviceInitialized indicates if the service is already initialized.
168     */
169    private static boolean serviceInitialized = false;
170
171    /**
172     * the provider instance that will be used for Debug service.
173     */
174    private static IDebugProvider debugProvider;
175
176    /**
177     * Constant string used as property key to look up the debug provider class
178     * name.
179     */
180    private static final String CONFIG_DEBUG_PROVIDER = 
181        "com.sun.identity.util.debug.provider";
182
183    /**
184     * Gets an existing instance of Debug for the specified debug name or a new
185     * one if no such instance already exists. If a Debug object has to be
186     * created, its level is set to the level defined in the
187     * <code>AMConfig.properties</code> file. The level can be changed later
188     * by using {@link #setDebug(int)} or {@link #setDebug(String)} methods.
189     * 
190     * @param debugName
191     *            name of the debug instances to be created
192     * @return a Debug instance corresponding to the specified debug name.
193     */
194    public static synchronized Debug getInstance(String debugName) {
195        Debug debug = (Debug)getDebugMap().get(debugName);
196        if (debug == null) {
197            debug = new Debug(getDebugProvider().getInstance(debugName));
198            getDebugMap().put(debugName, debug);
199        }
200        return debug;
201    }
202
203    /**
204     * Returns a collection of all Debug instances that exist in the system at
205     * the current instance. This is a live collection that will be updated as
206     * and when new Debug instances are created. Note that if an iterator is
207     * used, it could potentially cause a
208     * <code>ConcurrentModificationException</code> if during the process of
209     * iteration, the collection is modified by the system.
210     * 
211     * @return a collection of all Debug instances in the system.
212     */
213    public static Collection getInstances() {
214        return getDebugMap().values();
215    }
216
217    /**
218     * Gets the <code>Map</code> of all Debug instances being used in the
219     * system currently.
220     * 
221     * @return the <code>Map</code> of all Debug instances
222     */
223    private static Map getDebugMap() {
224        return debugMap;
225    }
226
227    /**
228     * Sets the provider instance to be used by Debug service.
229     * 
230     * @param provider
231     *            the <code>IDebugProvider</code> instance that is used by the
232     *            Debug service.
233     */
234    private static void setDebugProvider(IDebugProvider provider) {
235        debugProvider = provider;
236    }
237
238    /**
239     * Gets the configured debug provider being used by the Debug service.
240     * 
241     * @return the configured debug provider.
242     */
243    static IDebugProvider getDebugProvider() {
244        return debugProvider;
245    }
246
247    /**
248     * Initializes the Debug Service by locating the SPI implementations and
249     * instantiating the appropriate classes.
250     */
251    private static synchronized void initialize() {
252        if (!serviceInitialized) {
253            String providerName = SystemPropertiesManager.get(
254                CONFIG_DEBUG_PROVIDER);
255            IDebugProvider provider = null;
256            boolean providerLoadFailed = false;
257            if (providerName != null && providerName.trim().length() > 0) {
258                try {
259                    provider = (IDebugProvider) Class.forName(providerName)
260                            .newInstance();
261                } catch (ClassNotFoundException cnex) {
262                    providerLoadFailed = true;
263                } catch (InstantiationException iex) {
264                    providerLoadFailed = true;
265                } catch (IllegalAccessException iaex) {
266                    providerLoadFailed = true;
267                } catch (ClassCastException ccex) {
268                    providerLoadFailed = true;
269                }
270            }
271            if (provider == null) {
272                if (providerLoadFailed) {
273                    ResourceBundle bundle =com.sun.identity.shared.locale.Locale
274                            .getInstallResourceBundle("amUtilMsgs");
275                    System.err.println(bundle.getString(
276                            "com.iplanet.services.debug.invalidprovider"));
277                }
278                provider = new DebugProviderImpl();
279            }
280            setDebugProvider(provider);
281            serviceInitialized = true;
282        }
283    }
284
285    /* Instance fields and methods */
286
287    /**
288     * The instance of the actual debug service class as obtained from the
289     * configured provider.
290     */
291    private IDebug debugServiceInstance;
292
293    /**
294     * Convinience method to query the name being used for this Debug instance.
295     * The return value of this method is a string exactly equal to the name
296     * that was used while creating this instance.
297     * 
298     * @return the name of this Debug instance
299     */
300    public String getName() {
301        return getDebugServiceInstance().getName();
302    }
303
304    /**
305     * Checks if message debugging is enabled.
306     * 
307     * <p>
308     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
309     * application performance when abused. Particularly, note that Java
310     * evaluates arguments to <code>message()</code> even when debugging is
311     * turned off. It is recommended that <code>messageEnabled()</code> be
312     * called to check the debug state before invoking any
313     * <code>message()</code> methods to avoid unnecessary argument evaluation
314     * and maximize application performance.
315     * </p>
316     * 
317     * @return <code>true</code> if message debugging is enabled
318     *         <code>false</code> if message debugging is disabled
319     */
320    public boolean messageEnabled() {
321        return getDebugServiceInstance().messageEnabled();
322    }
323
324    /**
325     * Checks if warning debugging is enabled.
326     * 
327     * <p>
328     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
329     * application performance when abused. Particularly, note that Java
330     * evaluates arguments to <code>warning()</code> even when warning
331     * debugging is turned off. It is recommended that
332     * <code>warningEnabled()</code> be called to check the debug state before
333     * invoking any <code>warning()</code> methods to avoid unnecessary
334     * argument evaluation and maximize application performance.
335     * </p>
336     * 
337     * @return <code>true</code> if warning debugging is enabled
338     *         <code>false</code> if warning debugging is disabled
339     */
340    public boolean warningEnabled() {
341        return getDebugServiceInstance().warningEnabled();
342    }
343
344    /**
345     * Checks if error debugging is enabled.
346     * 
347     * <p>
348     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
349     * application performance when abused. Particularly, note that Java
350     * evaluates arguments to <code>error()</code> even when error debugging
351     * is turned off. It is recommended that <code>errorEnabled()</code> be
352     * called to check the debug state before invoking any <code>error()</code>
353     * methods to avoid unnecessary argument evaluation and maximize application
354     * performance.
355     * </p>
356     * 
357     * @return <code>true</code> if error debugging is enabled
358     *         <code>false</code> if error debugging is disabled
359     */
360    public boolean errorEnabled() {
361        return getDebugServiceInstance().errorEnabled();
362    }
363
364    /**
365     * Returns one of the five possible values:
366     * <ul>
367     * <li>Debug.OFF
368     * <li>Debug.ERROR
369     * <li>Debug.WARNING
370     * <li>Debug.MESSAGE
371     * <li>Debug.ON
372     * </ul>
373     * 
374     * @return the debug level
375     */
376    public int getState() {
377        return getDebugServiceInstance().getState();
378    }
379
380    /**
381     * Prints messages only when the debug state is either Debug.MESSAGE or
382     * Debug.ON.
383     * 
384     * <p>
385     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
386     * application performance when abused. Particularly, note that Java
387     * evaluates arguments to <code>message()</code> even when debugging is
388     * turned off. So when the argument to this method involves the String
389     * concatenation operator '+' or any other method invocation,
390     * <code>messageEnabled</code> <b>MUST</b> be used. It is recommended
391     * that the debug state be checked by invoking <code>messageEnabled()</code>
392     * before invoking any <code>message()</code> methods to avoid unnecessary
393     * argument evaluation and maximize application performance.
394     * </p>
395     * 
396     * @param msg
397     *            debug message.
398     * @see Debug#message(String, Throwable)
399     */
400    public void message(String msg) {
401        getDebugServiceInstance().message(msg, null);
402    }
403
404    /**
405     * <p>
406     * Prints debug and exception messages only when the debug state is either
407     * Debug.MESSAGE or Debug.ON. If the debug file is not accessible and
408     * debugging is enabled, the message along with a time stamp and thread info
409     * will be printed on <code>System.out</code>.
410     * </p>
411     * 
412     * <p>
413     * This method creates the debug file if does not exist; otherwise it starts
414     * appending to the existing debug file. When invoked for the first time on
415     * this object, the method writes a line delimiter of '*'s.
416     * </p>
417     * 
418     * <p>
419     * Note that the debug file will remain open until <code>destroy()</code>
420     * is invoked. To conserve file resources, you should invoke
421     * <code>destroy()</code> explicitly rather than wait for the garbage
422     * collector to clean up.
423     * </p>
424     * 
425     * <p>
426     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
427     * application performance when abused. Particularly, note that Java
428     * evaluates arguments to <code>message()</code> even when debugging is
429     * turned off. It is recommended that the debug state be checked by invoking
430     * <code>messageEnabled()</code> before invoking any
431     * <code>message()</code> methods to avoid unnecessary argument evaluation
432     * and to maximize application performance.
433     * </p>
434     * 
435     * @param msg
436     *            message to be printed. A newline will be appended to the
437     *            message before printing either to <code>System.out</code> or
438     *            to the debug file. If <code>msg</code> is null, it is
439     *            ignored.
440     * @param t
441     *            <code>Throwable</code>, on which
442     *            <code>printStackTrace</code> will be invoked to print the
443     *            stack trace. If <code>t</code> is null, it is ignored.
444     * @see Debug#error(String, Throwable)
445     */
446    public void message(String msg, Throwable t) {
447        getDebugServiceInstance().message(msg, t);
448    }
449
450    /**
451     * Prints warning messages only when debug level is greater than
452     * Debug.ERROR.
453     * 
454     * <p>
455     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
456     * application performance when abused. Particularly, note that Java
457     * evaluates arguments to <code>warning()</code> even when debugging is
458     * turned off. So when the argument to this method involves the String
459     * concatenation operator '+' or any other method invocation,
460     * <code>warningEnabled</code> <b>MUST</b> be used. It is recommended
461     * that the debug state be checked by invoking <code>warningEnabled()</code>
462     * before invoking any <code>warning()</code> methods to avoid unnecessary
463     * argument evaluation and to maximize application performance.
464     * </p>
465     * 
466     * @param msg
467     *            message to be printed. A newline will be appended to the
468     *            message before printing either to <code>System.out</code> or
469     *            to the debug file. If <code>msg</code> is null, it is
470     *            ignored.
471     * 
472     * @see Debug#warning(String, Throwable)
473     */
474    public void warning(String msg) {
475        getDebugServiceInstance().warning(msg, null);
476    }
477
478    /**
479     * Prints warning messages only when debug level is greater than
480     * Debug.ERROR.
481     * 
482     * <p>
483     * <b>NOTE:</b> Debugging is an IO intensive operation and may hurt
484     * application performance when abused. Particularly, note that Java
485     * evaluates arguments to <code>warning()</code> even when debugging is
486     * turned off. It is recommended that the debug state be checked by invoking
487     * <code>warningEnabled()</code> before invoking any
488     * <code>warning()</code> methods to avoid unnecessary argument evaluation
489     * and to maximize application performance.
490     * </p>
491     * 
492     * <p>
493     * If the debug file is not accessible and debugging is enabled, the message
494     * along with a time stamp and thread info will be printed on
495     * <code>System.out</code>.
496     * </p>
497     * 
498     * <p>
499     * This method creates the debug file if does not exist; otherwise it starts
500     * appending to the existing debug file. When invoked for the first time on
501     * this object, the method writes a line delimiter of '*'s.
502     * </p>
503     * 
504     * <p>
505     * Note that the debug file will remain open until <code>destroy()</code>
506     * is invoked. To conserve file resources, you should invoke
507     * <code>destroy()</code> explicitly rather than wait for the garbage
508     * collector to clean up.
509     * </p>
510     * 
511     * @param msg
512     *            message to be printed. A newline will be appended to the
513     *            message before printing either to <code>System.out</code> or
514     *            to the debug file. If <code>msg</code> is null, it is
515     *            ignored.
516     * 
517     * @param t
518     *            <code>Throwable</code>, on which
519     *            <code>printStackTrace()</code> will be invoked to print the
520     *            stack trace. If <code>t</code> is null, it is ignored.
521     */
522    public void warning(String msg, Throwable t) {
523        getDebugServiceInstance().warning(msg, t);
524    }
525
526    /**
527     * Prints error messages only when debug level is greater than DEBUG.OFF.
528     * 
529     * @param msg
530     *            message to be printed. A newline will be appended to the
531     *            message before printing either to <code>System.out</code> or
532     *            to the debug file. If <code>msg</code> is null, it is
533     *            ignored.
534     * 
535     * @see Debug#error(String, Throwable)
536     */
537    public void error(String msg) {
538        getDebugServiceInstance().error(msg, null);
539    }
540
541    /**
542     * Prints error messages only if debug state is greater than Debug.OFF. If
543     * the debug file is not accessible and debugging is enabled, the message
544     * along with a time stamp and thread info will be printed on
545     * <code>System.out</code>.
546     * </p>
547     * 
548     * <p>
549     * This method creates the debug file if does not exist; otherwise it starts
550     * appending to the existing debug file. When invoked for the first time on
551     * this object, the method writes a line delimiter of '*'s.
552     * </p>
553     * 
554     * <p>
555     * Note that the debug file will remain open until <code>destroy()</code>
556     * is invoked. To conserve file resources, you should invoke
557     * <code>destroy()</code> explicitly rather than wait for the garbage
558     * collector to clean up.
559     * </p>
560     * 
561     * @param msg
562     *            message to be printed. A newline will be appended to the
563     *            message before printing either to <code>System.out</code> or
564     *            to the debug file. If <code>msg</code> is null, it is
565     *            ignored.
566     * 
567     * @param t
568     *            <code>Throwable</code>, on which
569     *            <code>printStackTrace()</code> will be invoked to print the
570     *            stack trace. If <code>t</code> is null, it is ignored.
571     */
572    public void error(String msg, Throwable t) {
573        getDebugServiceInstance().error(msg, t);
574    }
575
576    /**
577     * Sets the debug capabilities based on the values of the
578     * <code>debugType</code> argument.
579     * 
580     * @param debugType
581     *            is any one of five possible values:
582     *            <ul>
583     *            <li><code>Debug.OFF</code>
584     *            <li><code>Debug.ERROR</code>
585     *            <li><code>Debug.WARNING</code>
586     *            <li><code>Debug.MESSAGE</code>
587     *            <li><code>Debug.ON</code>
588     *            </ul>
589     */
590    public void setDebug(int debugType) {
591        getDebugServiceInstance().setDebug(debugType);
592    }
593
594    /**
595     * Allows runtime modification of the backend used by this instance. 
596     * by resetting the debug instance to reinitialize itself.
597     * @param mf merge flag - on for creating a single debug file.
598     */
599    public void resetDebug(String mf) {
600        getDebugServiceInstance().resetDebug(mf);
601    }
602    /**
603     * Sets the debug capabilities based on the values of the
604     * <code>debugType</code> argument.
605     * 
606     * @param debugType
607     *            is any one of the following possible values:
608     *            <ul>
609     *            <li><code>Debug.STR_OFF</code>
610     *            <li><code>Debug.STR_ERROR</code>
611     *            <li><code>Debug.STR_WARNING</code>
612     *            <li><code>Debug.STR_MESSAGE</code>
613     *            <li><code>Debug.STR_ON</code>
614     *            </ul>
615     */
616    public void setDebug(String debugType) {
617        getDebugServiceInstance().setDebug(debugType);
618    }
619
620    /**
621     * Destroys the debug object, closes the debug file and releases any system
622     * resources. Note that the debug file will remain open until
623     * <code>destroy()</code> is invoked. To conserve file resources, you
624     * should invoke <code>destroy()</code> explicitly rather than wait for
625     * the garbage collector to clean up.
626     * 
627     * <p>
628     * If this object is accessed after <code>destroy()</code> has been
629     * invoked, the results are undefined.
630     * </p>
631     */
632    public void destroy() {
633        // No handling required
634    }
635
636    /**
637     * Setter for setting the actual debug service class which is obtained from
638     * the configured provider.
639     */
640    private void setDebugServiceInstance(IDebug debugServiceInstance) {
641        this.debugServiceInstance = debugServiceInstance;
642    }
643
644    /**
645     * Returns the actual debug service class.
646     * 
647     * @return The underlying debug service class.
648     */
649    private IDebug getDebugServiceInstance() {
650        return this.debugServiceInstance;
651    }
652
653    /**
654     * The sole constructor of the Debug instances. This constructor is declared
655     * private to ensure the use of the factory method provided in this class
656     * called {@link #getInstance(String)}.
657     */
658    private Debug(IDebug debugServiceInstance) {
659        setDebugServiceInstance(debugServiceInstance);
660    }
661
662    /* Static Initializer */
663    static {
664        initialize();
665    }
666}