/* File: Debug.java * Contains: Debugging tools * Author: Jeff Dalton * Created: January 1998 * Updated: Mon Nov 19 15:15:45 2001 by Jeff Dalton * Copyright: (c) 1998, AIAI, University of Edinburgh */ package ix.util; import java.util.*; import java.io.*; /** Class for useful static debugging tools */ public abstract class Debug { private Debug() { } // no instantiation /* * Simple debugging output */ /** * Global on/off control over the debugging output produced by * the note and noteln methods. */ public static boolean on = true; /** * The output destination used by note and noteln. Do not * assign directly to this variable. Call setNoteStream or * setNoteFile instead. */ public static PrintStream out = System.out; /** * note writes a string to Debug.out if Debug.on is true. * It is intetended to replace System.out.print calls, for * debugging output.

* * Unlike noteln, note does not print a newline after the message * and does not have variants that take different arguments. * The typical use of note is to use several calls to write a line * of output. One potential problem with using note is that * a different thread may print some other output between those * calls. */ public static void note(String message) { if (on) printNote(message); } /** * noteln writes a string, followed by a newline, to Debug.out * if Debug.on is true. It is intended to replace System.out.println * calls, for debugging output. noteln has variants that take more * than one argument. The arguments will be printed as strings * with single spaces between. The aim here is to avoid string * concatenation in the calls to noteln, so that the concatenation * will not occur when debugging output is turned off. */ public static void noteln(String message) { if (on) printlnNote(message); } public static void noteln(String message, Object whatever) { if (on) printlnNote(message + " " + whatever); } // Some things are not objects, alas public static void noteln(String message, int i) { if (on) printlnNote(message + " " + i); } // The following messages are synchronized, to ensure that each call // to note or noteln completes before a new one starts, and to ensure // that Debug.out isn't changed during one of these calls. The // stream classes may already provide enough synchronization for // the first case. private static synchronized void printNote(String message) { out.print(message); out.flush(); } private static synchronized void printlnNote(String message) { out.println(message); // Do we need out.flush()? } /* * Debugging output redirection */ /** * Sets the output destination for debugging notes. */ public static synchronized void setNoteStream(PrintStream s) { out = s; } /** * Sets the output destination for debugging notes. */ public static synchronized void setNoteFile(String filename) { try { // First, a stream to the file. FileOutputStream fout = new FileOutputStream(filename); // Then a PrintStream with flush-on-newline = true. out = new PrintStream(fout, true); } catch (IOException e) { Debug.warn("Failed to setNoteFile to \"" + filename + "\"\n" + "because " + e + "\n" + "so switching to System.out."); out = System.out; } } /* * Special-purpose debugging output routines */ /** * Note an exception, together with a backtrace. The note is always * printed to System.out or System.err, even if debug output has been * turned off or redirected to a file. */ public static synchronized void noteException(Exception e) { noteException(e, true); } /** * Note an exception, optionally with a backtrace. The note is always * printed to System.out or System.err, even if debug output has been * turned off or redirected to a file. */ public static synchronized void noteException(Exception e, boolean backtrace) { if (on) { noteln("\nException:", e); if (backtrace) e.printStackTrace(out); noteln(""); } if (!on || out != System.out) { System.err.println("\nException: " + e); if (backtrace) e.printStackTrace(System.err); System.err.println(""); } } /** * Use this to tell the user about minor problems. Warn prints * a message to System.err, followed by a backtrace for the current * thread. */ public static void warn(String message) { System.err.println("\nWarning: " + message + "\n"); Thread.dumpStack(); System.err.println(""); } /** * Use this to tell the user about problems that should not be * ignored and are not handled locally. * * @throws RuntimeException as notification of the problem. */ public static void error(String message) { System.err.println("\nWarning: " + message + "\n"); throw new RuntimeException(message); } /** * Numbers and prints the elements of an Enumeration on separate lines. */ public static synchronized void noteEnumeration(Enumeration e) { Debug.note("["); for (int i = 0; e.hasMoreElements(); i++) { Debug.note(i + ": " + e.nextElement() + "\n "); } Debug.noteln("]"); } /** * Prints the elements of an Enumeration on separate lines, with * an index number and and class name at the start of each line. */ public static synchronized void noteEnumerationClasses(Enumeration e) { Debug.note("["); for (int i = 0; e.hasMoreElements(); i++) { Object elt = e.nextElement(); Debug.note(i + " " + elt.getClass() + ": " + elt + "\n "); } Debug.noteln("]"); } /** * Prints the elements of an enumeration on separate lines with * a specified prefix at the start of each line. */ public static synchronized void noteElements(Enumeration e, String prefix) { while (e.hasMoreElements()) Debug.noteln(prefix, e.nextElement()); } /* * Assertions */ /** * assert checks a condition that should always be true and * throws an AssertionFailure if it is not. assert is typically * used when all of the following apply: the subsequent code * requires a condition to be true; in the absence of bugs, * the condition always will be true at that point; and it is * not obvious that the condition will be true.

* * AssertionFailure is a RuntimeException and so does not need to be * listed in the "throws" clauses of method definitions. One reason * for that is to avoid discouraging the use of assertions. If * AssertionFailure had to be declared, then adding an assertion * in a method that had none before would require nonlocal changes * in the code. * * @throws AssertionFailure as notification of the problem * @see AssertionFailure */ public static void assert(boolean cond) { if (!cond) { noteln("Assertion failed."); throw new AssertionFailure(); } } /** * A variant that allows a message that describes the assertion. * The message will be printed when the assertion fails and will * be included in the AssertionFailure exception. */ public static void assert(boolean cond, String message) { if (!cond) { noteln("Assertion failed:", message); throw new AssertionFailure(message); } } /** * A variant that allows a message that describes the assertion * plus an Object that the message is about. */ public static void assert(boolean cond, String message, Object item) { if (!cond) { String itemMessage = message + " " + item; noteln("Assertion failed:", itemMessage); throw new AssertionFailure(itemMessage); } } } /* ---------------------------- Change History ---------------------------- * (Who) (When) (What) * */