Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/flexstor/common/util/DiagnosticBase.java


1   /*
2    * DiagnosticBase.java
3    *
4    * Copyright $Date: 2003/08/11 02:22:30 $ FLEXSTOR.net Inc.
5    *
6    * This work is licensed for use and distribution under license terms found at
7    * http://www.flexstor.org/license.html
8    *
9    */
10  
11  package com.flexstor.common.util;
12  
13  import java.io.OutputStream;
14  import java.io.PrintWriter;
15  import java.io.StringWriter;
16  import java.io.Writer;
17  import java.text.SimpleDateFormat;
18  import java.util.Date;
19  import java.util.Hashtable;
20  import java.util.Properties;
21  import java.util.StringTokenizer;
22  import java.util.Vector;
23  
24  /**
25   * Revision 1.6 2000-09-28 : 22:51:00 Visesh
26   * This class now extends DiagnosticCategoryI instead of DiagnosticCategory
27   * Removed constructors particular to DiagnosticCategory when it was in the hiearchy
28   * Changed all method definations by changing the type of parameters from DiagnosticCategoryI
29   * to DiagnosticCategory
30   *
31   * DiagnosticBase is a utility class for tracing and debugging. It is not intended
32   * for error and exception handling. It provides methods to print, trace, and warn
33   * and also to check for conditions. One or more output streams can be registered
34   * so that output can be saved in a file and shown on the console simultaneously.<P>
35   * This is the base class without dependencies providing the main functionality.
36   * Diagnostic adds the capability of using a properties file for configuration.
37   */
38  public class DiagnosticBase
39     extends DiagnosticCategoryI
40  {
41     protected static final String   indent = "                                          ";
42  
43     protected static int         outLevel = 0;
44     protected static boolean     bPropertiesLoaded = false;
45     protected static boolean     bOutput           = false;
46     protected static boolean     bOutputConsole    = false;
47     protected static boolean     bPrintTime        = false;
48     protected static boolean     bPrintThreadId    = false;
49     protected static boolean     bChecking         = true;
50     protected static Vector      traceCategories   = new Vector();
51     protected static Vector      fileTraceCategories = new Vector();
52     protected static Properties  categoryTraceLevels = new Properties();
53  
54     /** Default time format: year-month-day 24hour:minute:second:millisecond */
55     protected static final String COL_SEPARARTOR               = " | ";
56     protected static final String DEFAULT_TIME_FORMAT          = "yyyy-MM-dd kk:mm:ss:SSS";
57     protected static       SimpleDateFormat timeFormat         = new SimpleDateFormat(DEFAULT_TIME_FORMAT);
58  
59     protected static PrintWriter[] outputDevices = new PrintWriter[0];
60     protected static Hashtable     outputDevicesCategory = new Hashtable(); // contains one output writer per category
61     protected static final OutputStream  systemOut = System.out;   // keep a handle on the original System.out
62  
63    /* public DiagnosticBase() { super(); }
64  
65     public DiagnosticBase(String name)
66     {
67          super(name);
68     }*/
69      
70     /**
71      * Adds an OutputStream as an output device
72      * @param outstream the output stream to write to, e.g. System.out
73      */
74     public static void addOutputDevice(OutputStream outstream)
75     {
76        addOutputDevice(new PrintWriter(outstream));
77     }
78  
79     /**
80      * Adds a writer as an output device
81      * @param writer the writer to write to
82      */
83     public static void addOutputDevice(Writer writer)
84     {
85        PrintWriter[] newDevices = null;
86  
87        if (outputDevices == null)
88        {
89           outputDevices = new PrintWriter[1];
90        }
91        else
92        {
93           newDevices = new PrintWriter[outputDevices.length+1];
94           System.arraycopy(outputDevices, 0, newDevices, 0, outputDevices.length);
95        }
96  
97        newDevices[newDevices.length-1] = new PrintWriter(writer);
98        outputDevices = newDevices;
99     }
100 
101    /**
102     * Adds an exclusive OutputStream as an output device for the specified category
103     * @param outstream the output stream to write to, e.g. System.out
104     * @param category a category for this output device
105     */
106    public static void addOutputDevice(DiagnosticCategory category, OutputStream outstream)
107    {
108       addOutputDevice(category, new PrintWriter(outstream));
109    }
110 
111    /**
112     * Adds an exclusive writer as an output device for the specified category
113     * @param outstream the output stream to write to, e.g. System.out
114     * @param category a category for this output device
115     */
116    public static void addOutputDevice(DiagnosticCategory category, PrintWriter writer)
117    {
118       outputDevicesCategory.put(category, writer);
119    }
120 
121 
122   /**
123    * Enables or disables output generation
124    */
125    public static void enableOutput(boolean enable)
126    {
127       bOutput = enable;
128    }
129 
130   /**
131    * Enables or disables the checking of conditions in precondition() and check()
132    */
133    public static void enableChecking(boolean enable)
134    {
135       bChecking = enable;
136    }
137 
138   /**
139    * Enables or disables the time stamp print
140    */
141    public static void enableTimeStamp(boolean enable)
142    {
143       bPrintTime = enable;
144    }
145 
146   /**
147    * Set the minimum threshold for trace and warning output.
148    *       0 is highest level
149    * +maxint is lowest level
150    *
151    * Setting this level to -1 will effectively turn off traces and warnings.
152    */
153    public static void setTraceLevel(int nLevel)
154    {
155       outLevel = nLevel;
156    }
157 
158    protected static int getTraceLevel()
159    {
160       return outLevel;
161    }
162    
163    public static int getTraceLevel(DiagnosticCategory category)
164    {
165       String sLevel = (String) categoryTraceLevels.get(category);
166       if (sLevel != null)
167       {
168          // convert the value to an int */
169          try
170          {
171             return Integer.parseInt(sLevel);
172          }
173          catch (NumberFormatException nfe)
174          {
175             return outLevel;
176          }
177       }
178       return outLevel;
179    }
180 
181    /**
182     * Adds a category for tracing and warnings.
183     * @param category a new category
184     */
185    public static void addTraceCategory(DiagnosticCategory category)
186    {
187       traceCategories.addElement(category);
188    }
189 
190    /**
191     * Removes a category for tracing and warnings.
192     * @param category the category to remove from the category list
193     */
194    public static void removeTraceCategory(DiagnosticCategory category)
195    {
196       traceCategories.removeElement(category);
197    }
198 
199   /**
200    * Assert a precondition before a method body run. Use this to describe assumed state and
201    * parameter values. A precondition is raised if the given condition is not true.
202    * The check is only performed if checking is enabled.
203    * @param bCondition the condition to check
204    * @param sDescription a text to describe the precondition
205    */
206    public static void precondition(boolean bCondition, String sDescription)
207       throws DiagnosticPreconditionException
208    {
209       //getProperties();
210       if (bChecking && !bCondition)
211       {
212          println("Precondition failed: " + sDescription);
213          throw new DiagnosticPreconditionException(sDescription);
214       }
215    }
216 
217   /**
218    * Check a condition within a method body. Use this to describe assumed results and state
219    * after internal operations. A check is raised if the given condition is not true.
220    * @param bCondition the condition to check
221    * @param sDescription a text to describe the condition
222    * @exception DiagnosticCheckException
223    */
224    public static void check(boolean bCondition, String sDescription)
225       throws DiagnosticCheckException
226    {
227       //getProperties();
228       if (bChecking && !bCondition)
229       {
230          println("Check failed: " + sDescription);
231          throw new DiagnosticCheckException(sDescription);
232       }
233    }
234 
235   /**
236    * Shorthand for causing an exception if the code reaches an unexpected location
237    * by rethrowing the exception
238    * @param ex the exception to throw
239    * @exception Exception
240    */
241    public static void fail(Exception ex)
242       throws Exception
243    {
244       println(ex.getMessage());
245       printStackTrace(ex);
246       throw(ex);
247    }
248 
249   /**
250    * Marks places where an exception is needed.
251    */
252    public static void needException()
253       throws DiagnosticCheckException
254    {
255       check(false, "Need Exception");
256    }
257 
258   /**
259    * Output a warning if the threshold level is high enough, and a condition is true, and general
260    * output is enabled
261    * @param nLevel       if level is less than or equal to the trace level, AND
262    * @param bCondition   if condition is true, output is generated
263    * @param sDescription text to output
264    */
265    public static void warn(int nLevel, boolean bCondition, String sDescription)
266    {
267       //getProperties();
268       if (bCondition && nLevel <= outLevel)
269          println("wn[" + nLevel + "] " + indent.substring(0,nLevel*2) + sDescription);
270    }
271 
272   /**
273    * Output a warning if the category is enabled, and a condition is true, and general
274    * output is enabled
275    * @param category    if category is registered, AND
276    * @param bCondition   if condition is true, output is generated
277    * @param sDescription text to output
278    */
279    public static void warn(DiagnosticCategory category, boolean bCondition, String sDescription)
280    {
281       //getProperties();
282       if (bCondition && (isRegisteredCategory(category) || !bPropertiesLoaded))
283          println(category, "wn[" + category.toString() + "] " + sDescription);
284    }
285 
286   /**
287    * Output a warning if the category is enabled, and general
288    * output is enabled
289    * @param category    if category is registered, output is generated
290    * @param sDescription text to output
291    */
292    public static void warn(DiagnosticCategory category, String sDescription)
293    {
294       warn(category, true, sDescription);
295    }
296 
297   /**
298    * Output a warning if the category is enabled,
299    * the threshold level is high enough,
300    * and a condition is true, and general output is enabled
301    * @param category    if category is registered, AND
302    * @param nLevel      if level is high enough, AND
303    * @param bCondition  if condition is true, output is generated
304    * @param sDescription text to output
305    */
306    public static void warn(DiagnosticCategory category, int nLevel, boolean bCondition, String sDescription)
307    {
308       //getProperties();
309       if (bCondition && ((isOutputLevel(category, nLevel) && isRegisteredCategory(category)) || !bPropertiesLoaded))
310          println(category, "wn[" + category.toString() + "." + nLevel +  "] " + sDescription);
311    }
312 
313   /**
314    * Output a trace if the threshold nLevel is high enough and general output is enabled
315    * @param nLevel      threshold level
316    * @param sDescription text to output
317    */
318    public static void trace(int nLevel, String sDescription)
319    {
320       //getProperties();
321       if (nLevel <= outLevel)
322          println("[" + nLevel + "]" + indent.substring(0,nLevel*2) + sDescription);
323    }
324 
325   /**
326    * Output a trace if the category and general output is enabled
327    * @param category a category to trace
328    * @param sDescription text to output
329    */
330    public static void trace(DiagnosticCategory category, String sDescription)
331    {
332       //getProperties();
333       if ( (outLevel > 0 && isRegisteredCategory(category)) || !bPropertiesLoaded )
334          println(category, "[" + category.toString() + "] " + sDescription);
335    }
336 
337   /**
338    * Output a trace if the category is enabled and general output is enabled
339    * @param category    category to be traced
340    * @param nLevel      threshold trace level
341    * @param sDescription text to output
342    */
343    public static void trace(DiagnosticCategory category, int nLevel, String sDescription)
344    {
345       //getProperties();
346       if ( (isOutputLevel(category, nLevel) && isRegisteredCategory(category)) || !bPropertiesLoaded )
347          println(category, "[" + category.toString() + "." + nLevel + "] " + indent.substring(0,nLevel*2) + sDescription);
348    }
349 
350   /**
351    * Print a stack trace of the Throwable to one PrintWriter. Used internally.
352    * @param writer a PrintWriter
353    * @param t the Trowable to trace
354    */
355    protected static void printOneStackTrace(PrintWriter writer, String sTime, Throwable t)
356    {
357       byte[]       baDelimiters = { 10, 13};    // linefeed, carriage return
358       StringWriter sw           = new StringWriter();
359 
360       t.printStackTrace(new PrintWriter(sw));
361       StringTokenizer st = new StringTokenizer(sw.toString(), new String(baDelimiters));
362 
363       synchronized(writer)
364       {
365          while (st.hasMoreTokens())
366          {
367             printOneLine(writer, sTime, st.nextToken());
368          }
369       }
370    }
371 
372   /**
373    * Print a stack trace of the Throwable to the output devices.
374    * @param t the Trowable to trace
375    */
376    public static void printStackTrace(Throwable t)
377    {
378       if (bOutput || !bPropertiesLoaded)
379       {
380          String sTime = timeFormat.format(new Date());
381          for (int i = 0; i < outputDevices.length; i++)
382          {
383             printOneStackTrace(outputDevices[i],sTime, t);
384          }
385       }
386    }
387 
388   /**
389    * Print a diagnostic stack trace of the current thread to the output devices.
390    */
391    public static void printStackTrace()
392    {
393       printStackTrace(new Exception("Diagnostic Stack Trace"));
394    }
395 
396   /**
397    * Print a stack trace of the Throwable to the output devices
398    * if the category is enabled.
399    * @param category    category to be traced
400    * @param t the Trowable to trace
401    */
402    public static void printStackTrace(DiagnosticCategory category, Throwable t)
403    {
404       if ((bOutput && isRegisteredCategory(category)) || !bPropertiesLoaded)
405       {
406          PrintWriter currentWriter = currentWriter = (PrintWriter)outputDevicesCategory.get(category);
407          if (currentWriter == null)
408          {
409             // print to general output
410             printStackTrace(t);
411          }
412          else
413          {
414             String sTime = timeFormat.format(new Date());
415             //print to specific print writer for category
416             printOneStackTrace(currentWriter, sTime, t);
417             // also print to console if flag is set
418             if (bOutputConsole)
419             {
420                printOneStackTrace(new PrintWriter(systemOut), sTime, t);
421             }
422          }
423       }  // if
424    }
425 
426   /**
427    * Print a stack trace of the Throwable to the output devices
428    * if the trace level is high enough.
429    * @param nLevel      threshold trace level
430    * @param t the Trowable to trace
431    */
432    public static void printStackTrace(int nLevel, Throwable t)
433    {
434       //getProperties();
435       if (nLevel <= outLevel)
436          printStackTrace(t);
437    }
438 
439   /**
440    * Print a stack trace of the Throwable to the output devices
441    * if the category is enabled and the trace level is high enough.
442    * @param category    category to be traced
443    * @param nLevel      threshold trace level
444    * @param t the Trowable to trace
445    */
446    public static void printStackTrace(DiagnosticCategory category, int nLevel, Throwable t)
447    {
448       //getProperties();
449       if ((isOutputLevel(category, nLevel) && isRegisteredCategory(category)) || !bPropertiesLoaded)
450          printStackTrace(category, t);
451    }
452 
453   /**
454    * Prints text to the output devices with a line feed.
455    * @param sText the text to output
456    */
457    public static void println(String sText)
458    {
459       if (bOutput)
460       {
461          String sTime = timeFormat.format(new Date());
462          for (int i = 0; i < outputDevices.length; i++)
463          {
464             printOneLine(outputDevices[i], sTime, sText);
465          }
466       }
467       else if (!bPropertiesLoaded)
468          System.out.println( sText );
469    }
470 
471    /**
472     * Print one line to one PrintWriter. Used internally.
473     * @param writer the writer to output to
474     * @param sText the text to print
475     */
476    protected static void printOneLine(PrintWriter writer, String sTime, String sText)
477    {
478       synchronized(writer)
479       {
480          if (bPrintTime)
481          {
482             writer.print(sTime);
483             writer.print(COL_SEPARARTOR);
484          }
485          if (bPrintThreadId)
486          {
487             writer.print(getThreadId());
488             writer.print(COL_SEPARARTOR);
489          }
490          writer.println(sText);
491          writer.flush();
492       }
493    }
494 
495   /**
496    * Checks if an output device is registered for this category,
497    * if so, print to it, otherwise use general output devices.
498    * Prints text to the output devices with a line feed.
499    * @param sText the text to output
500    * @param category  println for a category
501    */
502    protected static void println(DiagnosticCategory category, String sText)
503    {
504       if (bOutput)
505       {
506          PrintWriter currentWriter = (PrintWriter)outputDevicesCategory.get(category);
507          if (currentWriter == null)
508          {
509             // print to general output
510             println(sText);
511          }
512          else
513          {
514             String sTime = timeFormat.format(new Date());
515             //print to specific print writer for category
516             printOneLine(currentWriter, sTime, sText);
517             // also print to console if flag is set
518             if (bOutputConsole)
519             {
520                printOneLine(new PrintWriter(systemOut), sTime, sText);
521             }
522          }  // else
523       }  // if
524       else if (!bPropertiesLoaded)
525          System.out.println( sText );
526    }
527 
528   /**
529    * Prints text to the output devices without a line feed.
530    * @param sText the text to output
531    */
532 
533    /* made unavailable because it causes problems when multiple threads are printing
534    public static void print(String sText)
535    {
536       if (bOutput)
537          for (int i = 0; i < outputDevices.length; i++)
538          {
539             outputDevices[i].print(sText);
540             //outputDevices[i].flush();
541          }
542    }
543    */
544 
545    protected static String getThreadId()
546    {
547       return Thread.currentThread().getName();
548       //return Thread.currentThread().getName() + "(" + Thread.currentThread().getClass().getName();
549    }
550 
551    /**
552     * Prints the currently available memory.
553     * @param bRunGc Indicates if garbage collection is to be run
554     */
555    public static void printMemStatus(boolean bRunGc)
556    {
557       Runtime rt = Runtime.getRuntime();
558       println("Free memory : " + rt.freeMemory());
559       if (bRunGc)
560       {
561          rt.gc();
562          try{Thread.sleep(1000);}catch(InterruptedException e){}
563          println("    after gc: " + rt.freeMemory());
564       }
565    }
566 
567    protected static boolean isRegisteredCategory(DiagnosticCategory category)
568    {
569       return (fileTraceCategories.contains(category) || traceCategories.contains(category));
570    }
571 
572    protected static boolean isOutputLevel(DiagnosticCategory category, int nLevel)
573    {
574       // do we have a trace level specified for this category? */
575       String categoryLevel = (String)categoryTraceLevels.get(category);
576       if (categoryLevel != null)
577       {
578          // convert the value to an int */
579          try
580          {
581             int traceLevel = Integer.parseInt(categoryLevel);
582             // return whether the specified level is <= the category trace level */
583             return (nLevel <= traceLevel);
584          }
585          catch (NumberFormatException e)
586          {
587             // the value wasn't a number - ignore it
588          }
589       }
590       // at this point, we haven't found a valid category trace level, so use the global level. */
591       return (nLevel <= outLevel);
592    }
593    
594    public static boolean isOutputEnabled(DiagnosticCategory category)
595    {
596       if ( !isRegisteredCategory(category) )
597          return false;
598       else
599          return bOutput;
600    }
601 
602 }  // end of class
603