001: // Copyright 04/13/00 Sun Microsystems, Inc. All Rights Reserved.
002:
003: package com.sun.portal.util;
004:
005: import java.io.PrintWriter;
006: import java.text.DateFormat;
007: import java.util.HashMap;
008: import java.util.Map;
009:
010: // NOTE: Since JVM specs guarantee atomic access/updates to int variables
011: // (actually all variables except double and long), the design consciously
012: // avoids synchronized methods, particularly for message(). This is done to
013: // reduce the performance overhead of synchronized message() when debugging
014: // is disabled. This does not have serious side-effects other than an occasional
015: // invocation of message() missing concurrent update of 'debug'.
016:
017: /**
018: * <p>
019: * Allows a uniform interface to file debug and exception information in a
020: * uniform format. <code>Debug</code> supports different levels/states of
021: * filing debug information (in the ascending order): <code>OFF</code>,
022: * <code>ERROR</code>,<code>WARNING</code>,<code>MESSAGE</code> and
023: * <code>ON</code>. A given debug level/state is enabled if the debug
024: * state/level is set to at least that state/level. For example, if the debug
025: * state is <code>ERROR</code>, only errors will be filed. If the debug state
026: * is <code>WARNING</code>, only errors and warnings will be filed. If the
027: * debug state is <code>MESSAGE</code>, everything will be filed.
028: * <code>MESSAGE</code> and <code>ON</code> are of the same levels; the
029: * difference between them being <code>MESSAGE</code> writes to a file,
030: * whereas <code>ON</code> writes to System.out.
031: * </p>
032: *
033: * <p>
034: * Debug files are created in the directory specified by the property,
035: * <code>gateway.debug.dir</code>, in /etc/opt/SUNWportal/platform.conf file.
036: * The default value for this property is /var/opt/SUNWportal/debug.
037: * </p>
038: *
039: * <p>
040: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt application
041: * performance when abused. Particularly, note that Java evaluates the arguments
042: * to <code>message()</code> and <code>warning()</code> even when debugging
043: * is turned off. It is recommended that the debug state be checked before
044: * invoking any <code>message()</code> or <code>warning()</code> methods to
045: * avoid unnecessary argument evaluation and to maximize application
046: * performance.
047: * </p>
048: */
049: public class Debug {
050: private static final String DEFAULT_DEBUG_DIR = "/var/opt/SUNWportal/debug";
051:
052: private static final String DEBUG_LEVEL_ERROR = "error";
053:
054: /** flags the disabled debug state. */
055: public static final int OFF = 0;
056:
057: /**
058: * flags the state where error debugging is enabled. When debugging is set
059: * to less than <code>ERROR</code>, error debugging is also disabled.
060: */
061: public static final int ERROR = 1;
062:
063: /**
064: * flags the state where warning debugging is enabled, but message debugging
065: * is disabled. When debugging is set to less than <code>WARNING</code>,
066: * warning debugging is also disabled.
067: */
068: public static final int WARNING = 2;
069:
070: /** This state enables debugging of messages, warnings and errors. */
071: public static final int MESSAGE = 3;
072:
073: /**
074: * flags the enabled debug state for warnings, errors and messages. Printing
075: * to a file is disabled. All printing is done on System.out.
076: */
077: public static final int ON = 4;
078:
079: /**
080: * debugMap is a container of all active Debug objects. Log file name is the
081: * key and Debug is the value of this map.
082: */
083: private static Map debugMap = new HashMap();
084:
085: private static DateFormat dateFormat;
086:
087: private final String debugName;
088:
089: private PrintWriter debugFile = null;
090:
091: private int debug = Debug.OFF;
092:
093: static {
094: dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT,
095: DateFormat.LONG, java.util.Locale.US);
096: }
097:
098: /**
099: * This constructor takes as an argument the name of the debug file. The
100: * debug file is neither created nor opened until the first time
101: * <code>message()</code>,<code>warning()</code> or
102: * <code>error()</code> is invoked and the debug state is neither
103: * <code>OFF</code> nor <code>ON</code>.
104: * <p>
105: * <b>NOTE: </b>The recommended and preferred method to create Debug objects
106: * is <code>getInstance(String)</code>. This constructor may be
107: * deprecated in future.
108: * </p>
109: *
110: * @param debugFileName
111: * name of the debug file to create or use
112: * @see Debug#getInstance
113: */
114: public Debug(String debugName) {
115: /*
116: * File dirname = new File(getDebugBaseDir()); if (!dirname.exists()) {
117: * dirname.mkdirs(); }
118: */
119: // EOC :: Lihue drop 1
120: this .debugName = debugName;
121:
122: synchronized (debugMap) {
123: // explicitly ignore any duplicate instances.
124: debugMap.put(debugName, this );
125: }
126: }
127:
128: /**
129: * Gets an existing instance of Debug for the specified debug file or a new
130: * one if no such instance already exists.
131: */
132: public static synchronized Debug getInstance(String debugName) {
133: Debug debugObj = (Debug) debugMap.get(debugName);
134: if (debugObj == null) {
135: debugObj = new Debug(debugName);
136: }
137: return debugObj;
138: }
139:
140: /**
141: * Checks if message debugging is enabled.
142: *
143: * <p>
144: * <b>NOTE: </b> It is recommended that <code>messageEnabled()</code> be
145: * used instead of <code>debugEnabled()</code> as the former is more
146: * intuitive. </>
147: *
148: * @return <code>true</code> if message debugging is enabled
149: * <code>false</code> if message debugging is disabled
150: *
151: * @see Debug#messageEnabled
152: */
153: public boolean debugEnabled() {
154: return (debug > Debug.WARNING);
155: }
156:
157: /**
158: * Checks if message debugging is enabled.
159: *
160: * <p>
161: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
162: * application performance when abused. Particularly, note that Java
163: * evaluates arguments to <code>message()</code> even when debugging is
164: * turned off. It is recommended that <code>messageEnabled()</code> be
165: * called to check the debug state before invoking any
166: * <code>message()</code> methods to avoid unnecessary argument evaluation
167: * and maximize application performance.
168: * </p>
169: *
170: * @return <code>true</code> if message debugging is enabled
171: * <code>false</code> if message debugging is disabled
172: */
173: public boolean messageEnabled() {
174: return (debug > Debug.WARNING);
175: }
176:
177: /**
178: * Checks if warning debugging is enabled.
179: *
180: * <p>
181: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
182: * application performance when abused. Particularly, note that Java
183: * evaluates arguments to <code>warning()</code> even when warning
184: * debugging is turned off. It is recommended that
185: * <code>warningEnabled()</code> be called to check the debug state before
186: * invoking any <code>warning()</code> methods to avoid unnecessary
187: * argument evaluation and maximize application performance.
188: * </p>
189: *
190: * @return <code>true</code> if warning debugging is enabled
191: * <code>false</code> if warning debugging is disabled
192: */
193: public boolean warningEnabled() {
194: return (debug > Debug.ERROR);
195: }
196:
197: public boolean errorEnabled() {
198: return (debug > Debug.OFF);
199: }
200:
201: /**
202: * Returns one of the five possible values:
203: * <p>
204: * <code>Debug.OFF</code>
205: * <p>
206: * <p>
207: * <code>Debug.ERROR</code>
208: * <p>
209: * <p>
210: * <code>Debug.WARNING</code>
211: * <p>
212: * <p>
213: * <code>Debug.MESSAGE</code>
214: * <p>
215: * <p>
216: * <code>Debug.ON</code>
217: * <p>
218: */
219: public int getState() {
220: return debug;
221: }
222:
223: /**
224: * Prints messages only when the debug state is either DEBUG.MESSAGE or
225: * Debug.ON.
226: *
227: * <p>
228: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
229: * application performance when abused. Particularly, note that Java
230: * evaluates arguments to <code>message()</code> even when debugging is
231: * turned off. It is recommended that the debug state be checked by invoking
232: * <code>messageEnabled()</code> before invoking any
233: * <code>message()</code> methods to avoid unnecessary argument evaluation
234: * and maximize application performance.
235: * </p>
236: *
237: * @see Debug#message(String msg, Throwable t)
238: */
239: public void message(String msg) {
240: if (debug > Debug.WARNING) {
241: message(msg, null);
242: }
243: }
244:
245: /**
246: * <p>
247: * Prints debug and exception messages only when the debug state is either
248: * DEBUG.MESSAGE or Debug.ON. If the debug file is not accessible and
249: * debugging is enabled, the message along with a timestamp and thread info
250: * will be printed on <code>System.out</code>.
251: * </p>
252: *
253: * <p>
254: * This method creates the debug file if does not exist; otherwise it starts
255: * appending to the existing debug file. When invoked for the first time on
256: * this object, the method writes a line delimiter of '*'s.
257: * </p>
258: *
259: * <p>
260: * Note that the debug file will remain open until <code>destroy()</code>
261: * is invoked. To conserve file resources, you should invoke
262: * <code>destroy()</code> explicitly rather than wait for the garbage
263: * collector to clean up.
264: * </p>
265: *
266: * <p>
267: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
268: * application performance when abused. Particularly, note that Java
269: * evaluates arguments to <code>message()</code> even when debugging is
270: * turned off. It is recommended that the debug state be checked by invoking
271: * <code>messageEnabled()</code> before invoking any
272: * <code>message()</code> methods to avoid unnecessary argument evaluation
273: * and to maximize application performance.
274: * </p>
275: *
276: * @param msg
277: * message to be printed. A newline will be appended to the
278: * message before printing either to <code>System.out</code> or
279: * to the debug file. If <code>msg</code> is null, it is
280: * ignored.
281: *
282: * @param t
283: * Throwable, on which <code>printStackTrace</code> will be
284: * invoked to print the stack trace. If <code>t</code> is null,
285: * it is ignored.
286: *
287: * @see Debug#error(String msg, Throwable t)
288: */
289: public void message(String msg, Throwable t) {
290: if (debug > Debug.WARNING) {
291: formatAndWrite(null, msg, t);
292: }
293: }
294:
295: /**
296: * Prints warning messages only when debug level is greater than
297: * DEBUG.ERROR.
298: *
299: * <p>
300: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
301: * application performance when abused. Particularly, note that Java
302: * evaluates arguments to <code>warning()</code> even when debugging is
303: * turned off. It is recommended that the debug state be checked by invoking
304: * <code>warningEnabled()</code> before invoking any
305: * <code>warning()</code> methods to avoid unnecessary argument evaluation
306: * and to maximize application performance.
307: * </p>
308: *
309: * @see Debug#warning(String msg, Throwable t)
310: */
311: public void warning(String msg) {
312: if (debug > Debug.ERROR) {
313: formatAndWrite("WARNING: ", msg, null);
314: }
315: }
316:
317: /**
318: * Prints warning messages only when debug level is greater than
319: * DEBUG.ERROR.
320: *
321: * <p>
322: * <b>NOTE: </b> Debugging is an IO intensive operation and may hurt
323: * application performance when abused. Particularly, note that Java
324: * evaluates arguments to <code>warning()</code> even when debugging is
325: * turned off. It is recommended that the debug state be checked by invoking
326: * <code>warningEnabled()</code> before invoking any
327: * <code>warning()</code> methods to avoid unnecessary argument evaluation
328: * and to maximize application performance.
329: * </p>
330: *
331: * <p>
332: * If the debug file is not accessible and debuging is enabled, the message
333: * along with a timestamp and thread info will be printed on
334: * <code>System.out</code>.
335: * </p>
336: *
337: * <p>
338: * This method creates the debug file if does not exist; otherwise it starts
339: * appending to the existing debug file. When invoked for the first time on
340: * this object, the method writes a line delimiter of '*'s.
341: * </p>
342: *
343: * <p>
344: * Note that the debug file will remain open until <code>destroy()</code>
345: * is invoked. To conserve file resources, you should invoke
346: * <code>destroy()</code> explicitly rather than wait for the garbage
347: * collector to clean up.
348: * </p>
349: *
350: * @param msg
351: * message to be printed. A newline will be appended to the
352: * message before printing either to <code>System.out</code> or
353: * to the debug file. If <code>msg</code> is null, it is
354: * ignored.
355: *
356: * @param t
357: * Throwable, on which <code>printStackTrace()</code> will be
358: * invoked to print the stack trace. If <code>t</code> is null,
359: * it is ignored.
360: */
361: public void warning(String msg, Throwable t) {
362: if (debug > Debug.ERROR) {
363: formatAndWrite("WARNING: ", msg, t);
364: }
365: }
366:
367: /**
368: * Prints error messages only when debug level is greater than DEBUG.OFF.
369: *
370: * @see Debug#error(String msg, Throwable t)
371: */
372: public void error(String msg) {
373: if (debug > Debug.OFF) {
374: formatAndWrite("ERROR: ", msg, null);
375: }
376: }
377:
378: /**
379: * Prints error messages only if debug state is greater than Debug.OFF. If
380: * the debug file is not accessible and debugging is enabled, the message
381: * along with a timestamp and thread info will be printed on
382: * <code>System.out</code>.
383: * </p>
384: *
385: * <p>
386: * This method creates the debug file if does not exist; otherwise it starts
387: * appending to the existing debug file. When invoked for the first time on
388: * this object, the method writes a line delimiter of '*'s.
389: * </p>
390: *
391: * <p>
392: * Note that the debug file will remain open until <code>destroy()</code>
393: * is invoked. To conserve file resources, you should invoke
394: * <code>destroy()</code> explicitly rather than wait for the garbage
395: * collector to clean up.
396: * </p>
397: *
398: * @param msg
399: * message to be printed. A newline will be appended to the
400: * message before printing either to <code>System.out</code> or
401: * to the debug file. If <code>msg</code> is null, it is
402: * ignored.
403: *
404: * @param t
405: * Throwable, on which <code>printStackTrace()</code> will be
406: * invoked to print the stack trace. If <code>t</code> is null,
407: * it is ignored.
408: */
409: public void error(String msg, Throwable t) {
410: if (debug > Debug.OFF) {
411: formatAndWrite("ERROR: ", msg, t);
412: }
413: }
414:
415: private void formatAndWrite(String prefix, String msg, Throwable t) {
416: /*
417: * if (debug == Debug.ON) { if (msg != null) { if (prefix == null) {
418: * System.out.println(msg); } else { System.out.println(prefix + msg); } }
419: * if (t != null) { System.out.println(t.getMessage());
420: * t.printStackTrace(System.out); } return; }
421: * // The default capacity of StringBuffer in StringWriter is 16, but
422: * we // know for sure that the minimum header size is about 35. Hence,
423: * to // avoid reallocation allocate at least 160 chars.
424: *
425: * StringWriter swriter = new StringWriter(160); PrintWriter buf = new
426: * PrintWriter(swriter, true); synchronized (dateFormat) {
427: * buf.write(dateFormat.format(new Date())); } buf.write(": ");
428: * buf.write(Thread.currentThread().toString()); buf.write("\n"); if
429: * (prefix != null) { buf.write(prefix); } if (msg != null) {
430: * buf.write(msg); } if (t != null) { buf.write("\n");
431: * t.printStackTrace(buf); } buf.flush();
432: *
433: * write(swriter.toString());
434: */
435:
436: }
437:
438: /**
439: * Actually writes to the debug file. If it cannot write to the debug file,
440: * it turn off debugging.
441: */
442: private synchronized void write(String msg) {
443: /*
444: * try { // debugging is enabled. // First, see if the debugFile is
445: * already open. If not, open it now.
446: *
447: * if (debugFile == null) { // open file in append mode FileOutputStream
448: * fos = new FileOutputStream(getDebugBaseDir() + "/" + debugName,
449: * true); debugFile = new PrintWriter(new BufferedWriter(new
450: * OutputStreamWriter(fos, "UTF8")), true); // autoflush // enabled
451: *
452: * debugFile.println("******************************************************"); }
453: *
454: * debugFile.println(msg); } catch (IOException e) { //
455: * System.err.println(msg); System.err.println("Disabling debug log : " +
456: * debugName);
457: * // turn off debugging because debugFile is not accessible debug =
458: * Debug.OFF; }
459: */}
460:
461: /**
462: * Sets the debug capabilities based on the values of the debugType
463: * argument.
464: *
465: * @param debugType
466: * is any one of five possible values:
467: * <p>
468: * <code>Debug.OFF</code>
469: * <p>
470: * <p>
471: * <code>Debug.ERROR</code>
472: * <p>
473: * <p>
474: * <code>Debug.WARNING</code>
475: * <p>
476: * <p>
477: * <code>Debug.MESSAGE</code>
478: * <p>
479: * <p>
480: * <code>Debug.ON</code>
481: * <p>
482: */
483: public void setDebug(int debugType) {
484: switch (debugType) {
485: case Debug.OFF:
486: case Debug.ERROR:
487: case Debug.WARNING:
488: case Debug.MESSAGE:
489: case Debug.ON:
490: debug = debugType;
491: break;
492:
493: default:
494: // ignore invalid debugType values
495: break;
496: }
497: }
498:
499: /**
500: * Enables or disables degbugging based on the value of debug attribute,
501: * gateway.debug, in the platform config file,
502: * /etc/opt/SUNWportal/platform.conf. If the attribute is not defined,
503: * debugging is disabled by default.
504: */
505: public void setDebug() {
506: try {
507: setDebug(DEBUG_LEVEL_ERROR);
508: } catch (Exception ex) {
509: System.out.println("Error getting debug attribute: ");
510: ex.printStackTrace();
511: }
512: }
513:
514: /**
515: * Sets the debug capabilities based on the values of the debugType
516: * argument.
517: *
518: * @param debugType
519: * is any one of the following possible values:
520: * <p>
521: * off - debugging is disabled
522: * </p>
523: * <p>
524: * on - all debugging is enabled and written to
525: * <code>System.out</code>
526: * </p>
527: * <p>
528: * message - message debugging is enabled and written to the
529: * debug file
530: * </p>
531: * <p>
532: * warning - warning debugging is enabled and written to the
533: * debug
534: * </p>
535: * file
536: * </p>
537: * <p>
538: * error - error debugging is enabled and written to the debug
539: * </p>
540: * file
541: * </p>
542: */
543: public void setDebug(String debugType) {
544: if (debugType == null)
545: return;
546: debug = Debug.ERROR;
547: }
548:
549: /**
550: * Destroys the debug object, closes the debug file and releases any system
551: * resources. Note that the debug file will remain open until
552: * <code>destroy()</code> is invoked. To conserve file resources, you
553: * should invoke <code>destroy()</code> explicitly rather than wait for
554: * the garbage collector to clean up.
555: *
556: * <p>
557: * If this object is accessed after <code>destroy()</code> has been
558: * invoked, the results are undefined.
559: * </p>
560: */
561: public void destroy() {
562: finalize();
563: }
564:
565: /** Flushes and then closes the debug file. */
566: protected void finalize() {
567: synchronized (debugMap) {
568: debugMap.remove(debugName);
569: }
570:
571: synchronized (this ) {
572: if (debugFile == null) {
573: return;
574: }
575:
576: debug = Debug.OFF;
577: debugFile.flush();
578: debugFile.close();
579: debugFile = null;
580: }
581: }
582:
583: private String getDebugBaseDir() {
584: try {
585: return DEFAULT_DEBUG_DIR;
586: } catch (Exception ex) {
587: System.out.println("Error setting basedir: ");
588: ex.printStackTrace();
589: }
590: return null;
591: }
592:
593: private static final String sccsID = "@(#)Debug.java 1.20 00/04/13 Sun Microsystems, Inc.";
594: }
|