
/* **************************************************************************

  $Archive: /njcl/src/com/novell/java/util/Debug.java $
  $Revision: 2 $
  $Modtime: 4/23/98 11:34a $

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

package com.novell.java.util;


import java.io.*;

import java.util.*;

import javax.naming.NamingException;

import com.novell.java.lang.HasRootCause;
import com.novell.java.lang.HasRootCauses;


/** @internal
 *
 */
public class Debug
{
   public static boolean debug               = false;
   public static boolean assert              = false;
   public static boolean exitOnAssert        = false;
   public static boolean threads             = true;
   public static boolean quiet               = false;
   public static boolean outputToFile        = false;
   private static boolean traceInstructions  = false;
   private static boolean traceMethods       = false;
   private static PrintStream oriout = System.out;
   private static PrintStream orierr = System.err;

   synchronized static public void setOutput (
         String file)
   {
      FileOutputStream fout = null;
      try
      {
         fout = new FileOutputStream(file, true);
      }
      catch (IOException e)
      {
         ignoreException("DEBUG.setOutput()", e);
         return;
      }
      System.setOut(new PrintStream(fout));
      System.setErr(new PrintStream(fout));
      outputToFile = true;
   }

   synchronized static public void clearOutput ()
   {
      System.setOut(oriout);
      System.setErr(orierr);
      outputToFile = false;
   }

   synchronized static public void assert (
         boolean condition,
         String description)
   {
      if (assert)
      {
         if (!condition)
         {
            println("ASSERT FAILURE: " + description);
            if (exitOnAssert)
            {
               Thread.dumpStack();
               System.exit(-1);
            }
         }
      }
   }

   synchronized static public void traceOff ()
   {
      if (traceInstructions)
         Runtime.getRuntime().traceInstructions(false);
      if (traceMethods)
         Runtime.getRuntime().traceMethodCalls(false);
   }

   synchronized static public void traceOn ()
   {
      if (traceInstructions)
         Runtime.getRuntime().traceInstructions(true);
      if (traceMethods)
         Runtime.getRuntime().traceMethodCalls(true);
   }

   synchronized static public void traceInstructions (boolean trace)
   {
      traceInstructions = trace;
      Runtime.getRuntime().traceInstructions(traceInstructions);
   }

   synchronized static public void traceMethods (boolean trace)
   {
      traceMethods = trace;
      Runtime.getRuntime().traceMethodCalls (traceMethods);
   }

   synchronized static public boolean traceInstructionsOn ()
   {
      return traceInstructions;
   }

   synchronized static public boolean traceMethodsOn ()
   {
      return traceMethods;
   }

   synchronized static public void writeDebugProperties (String name)
   {
      try
      {
         Properties p = new Properties();
         p.put("debug",             new Boolean(debug).toString());
         p.put("assert",            new Boolean(assert).toString());
         p.put("exitOnAssert",      new Boolean(exitOnAssert).toString());
         p.put("threads",           new Boolean(threads).toString());
         p.put("quiet",             new Boolean(quiet).toString());
         p.put("traceInstructions", new Boolean(traceInstructions).toString());
         p.put("traceMethods",      new Boolean(traceMethods).toString());

         FileOutputStream out = new FileOutputStream(name);
         p.save(out, "Debug properties");
         out.close();
      }
      catch (IOException e)
      {
         // Ignore
      }
   }

   synchronized static public void readDebugProperties (String name)
   {
      try
      {
         Properties p = new Properties();
         FileInputStream in = new FileInputStream(name);
         boolean traceInstructions, traceMethods;
         p.load(in);
         in.close();
         debug    = new Boolean(
            p.getProperty("debug",              "false")).booleanValue();
         assert = new Boolean(
            p.getProperty("assert",             "false")).booleanValue();
         exitOnAssert = new Boolean(
            p.getProperty("exitOnAssert",       "false")).booleanValue();
         threads  = new Boolean(
            p.getProperty("threads",            "false")).booleanValue();
         quiet    = new Boolean(
            p.getProperty("quiet",              "false")).booleanValue();
         traceInstructions = new Boolean(
            p.getProperty("traceInstructions",  "false")).booleanValue();
         traceMethods = new Boolean(
            p.getProperty("traceMethods",       "false")).booleanValue();
         traceInstructions(traceInstructions);
         traceMethods(traceMethods);
      }
      catch (IOException e)
      {
         // Ignore
      }
   }

   /**
    * Dump a class hierarchy if debug true.
    */
   synchronized static public void dumpParents (Class c, int indent)
   {
      if (debug)
      {
         StringBuffer pad = new StringBuffer();
         for (int j = 0; j < indent; j++)
            pad.append(' ');

         Class[] parents = c.getClasses();
         for (int i = 0; i < parents.length; i++)
         {
            Class parent = parents[i];
            println(pad + parent.getName());
            dumpParents(parent, indent+1);
         }
      }
   }

   /**
    * Dump members of a class if debug true.
    */
   synchronized static public void dumpMembers (Class c, int indent)
   {
      if (debug)
      {
         StringBuffer pad = new StringBuffer ();
         for (int j = 0; j < indent; j++)
            pad.append(' ');

         Class[] members = c.getDeclaredClasses();
         for (int i = 0; i < members.length; i++)
         {
            Class member = members[i];
            println(pad + member.getName());
            dumpMembers(member, indent+1);
         }
      }
   }

   /**
    * Report that an exception is being ignored if debug true.
    */
   synchronized static public void ignoreException (Throwable e)
   {
      ignoreException("", e);
   }

   /**
    * Report that an exception is being ignored if debug true.
    */
   synchronized static public void ignoreException (
         String context,
         Throwable e)
   {
      if (debug)
      {
         if (quiet)
            ignoreExceptionQuietly(context, e);
         else
         {
            println("IGNORING EXCEPTION:" + context + ":");
            dumpException(e);
         }
      }
   }

   /**
    * Report that an exception is being ignored if debug true.
    */
   synchronized static public void ignoreExceptionQuietly (
         Throwable e)
   {
      ignoreExceptionQuietly("", e);
   }

   /**
    * Report that an exception is being ignored if debug true.
    */
   synchronized static public void ignoreExceptionQuietly (
         String context,
         Throwable e)
   {
      if (debug)
      {
         println("IGNORING EXCEPTION:" + context + ":");
         println(e.toString());
      }
   }

   /*
    * Print with beep if debug true
    */
   synchronized static public void printlnBeep (
         String output)
   {
      println("\007" + output);
   }

   synchronized static public void dumpException (
         Throwable e)
   {
      System.out.flush();
      System.err.flush();
      System.out.println("\nException...");
      e.printStackTrace();
      while (null != e)
      {
         if (e instanceof HasRootCauses)
         {
            println("\nRoot causes...");
            Enumeration enum = ((HasRootCauses)e).getRootCauses();
            while (enum.hasMoreElements())
            {
               dumpException((Throwable)enum.nextElement());
            }
         }
         if (e instanceof HasRootCause)
            e = ((HasRootCause)e).getRootCause();
         else if (e instanceof NamingException)
            e = ((NamingException) e).getRootCause ();
         else
            e = null;
         if (null != e)
         {
             println("\nRoot cause...");
             e.printStackTrace();
         }
      }
      System.err.flush();
      System.out.flush();
   }

   synchronized public static void dumpThreads ()
   {
      if (debug)
      {
         println("Current threads:");
         ThreadGroup tg = Thread.currentThread().getThreadGroup();
         while (null != tg.getParent())
            tg = tg.getParent();

         Thread[] threads = new Thread[tg.activeCount()];
         int count = tg.enumerate(threads, true);
         for (int i = 0; i < count; i++)
         {
            Thread t = threads[i];
            println("   " + t.getName());
         }
      }
   }

   synchronized public static String getShortThreadID ()
   {
      // FIX: Need to get unique thread id
      String s ="0x" + Integer.toHexString(Thread.currentThread().hashCode());
      return s;
   }

   synchronized public static void print (String msg)
   {
      if(debug)
         System.out.println(msg);
   }

   synchronized public static void println (String msg)
   {
      if (debug)
      {
         if (threads)
         {
            System.out.println (getShortThreadID () + ":" + msg);
         }
         else
         {
            System.out.println (msg);
         }
      }
   }

} /* Debug */


