Java/Development Class/Debug

Материал из Java эксперт
Перейти к: навигация, поиск

A bean that can be used to keep track of a counter

   
/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
import java.io.Serializable;

/**
 * A bean that can be used to keep track of a counter.
 * <p/>
 * Since it is an Iterator it can be used by the iterator tag
 *
 * @author Rickard &Ouml;berg (rickard@middleware-company.ru)
 * @version $Revision: 1282 $
 * @see <related>
 */
public class Counter implements java.util.Iterator, Serializable {
    boolean wrap = false;
    // Attributes ----------------------------------------------------
    long first = 1;
    long current = first;
    long interval = 1;
    long last = -1;

    public void setAdd(long addition) {
        current += addition;
    }
    public void setCurrent(long current) {
        this.current = current;
    }
    public long getCurrent() {
        return current;
    }
    public void setFirst(long first) {
        this.first = first;
        current = first;
    }
    public long getFirst() {
        return first;
    }
    public void setInterval(long interval) {
        this.interval = interval;
    }
    public long getInterval() {
        return interval;
    }
    public void setLast(long last) {
        this.last = last;
    }
    public long getLast() {
        return last;
    }
    // Public --------------------------------------------------------
    public long getNext() {
        long next = current;
        current += interval;
        if (wrap && (current > last)) {
            current -= ((1 + last) - first);
        }
        return next;
    }
    public long getPrevious() {
        current -= interval;
        if (wrap && (current < first)) {
            current += (last - first + 1);
        }
        return current;
    }
    public void setWrap(boolean wrap) {
        this.wrap = wrap;
    }
    public boolean isWrap() {
        return wrap;
    }
    public boolean hasNext() {
        return ((last == -1) || wrap) ? true : (current <= last);
    }
    public Object next() {
        return new Long(getNext());
    }
    public void remove() {
        // Do nothing
    }
}
///////////////////
/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package com.opensymphony.webwork.util;
import junit.framework.TestCase;

/**
 * User: plightbo
 * Date: Jan 7, 2004
 * Time: 7:55:35 PM
 */
public class CounterTest extends TestCase {
    Counter c = new Counter();

    public void testCurrentAfterNext() {
        long next = c.getNext();
        long current = c.getCurrent();
        assertEquals(next + 1, current);
    }
    public void testCurrentBeforeNext() {
        long current = c.getCurrent();
        long next = c.getNext();
        assertEquals(current, next);
    }
    public void testWrap() {
        c.setWrap(true);
        c.setLast(1);
        long a = c.getNext();
        long b = c.getNext();
        assertEquals(1, a);
        assertEquals(1, b);
    }
}





A long integer counter class

   
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.Serializable;
/**
 * A long integer counter class.
 * 
 * @version <tt>$Revision: 2800 $</tt>
 * @author 
 */
public class LongCounter implements Serializable, Cloneable {
  /** The serialVersionUID */
  private static final long serialVersionUID = 1615297462859270139L;
  /** The current count */
  private long count;
  /**
   * Construct a LongCounter with a starting value.
   * 
   * @param count
   *          Starting value for counter.
   */
  public LongCounter(final long count) {
    this.count = count;
  }
  /**
   * Construct a LongCounter.
   */
  public LongCounter() {
  }
  /**
   * Increment the counter. (Optional operation)
   * 
   * @return The incremented value of the counter.
   */
  public long increment() {
    return ++count;
  }
  /**
   * Decrement the counter. (Optional operation)
   * 
   * @return The decremented value of the counter.
   */
  public long decrement() {
    return --count;
  }
  /**
   * Return the current value of the counter.
   * 
   * @return The current value of the counter.
   */
  public long getCount() {
    return count;
  }
  /**
   * Reset the counter to zero. (Optional operation)
   */
  public void reset() {
    this.count = 0;
  }
  /**
   * Check if the given object is equal to this.
   * 
   * @param obj
   *          Object to test equality with.
   * @return True if object is equal to this.
   */
  public boolean equals(final Object obj) {
    if (obj == this)
      return true;
    if (obj != null && obj.getClass() == getClass()) {
      return ((LongCounter) obj).count == count;
    }
    return false;
  }
  /**
   * Return a string representation of this.
   * 
   * @return A string representation of this.
   */
  public String toString() {
    return String.valueOf(count);
  }
  /**
   * Return a cloned copy of this object.
   * 
   * @return A cloned copy of this object.
   */
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      throw new InternalError();
    }
  }
  // ///////////////////////////////////////////////////////////////////////
  // Wrappers //
  // ///////////////////////////////////////////////////////////////////////
  /**
   * Base wrapper class for other wrappers.
   */
  private static class Wrapper extends LongCounter {
    /** The serialVersionUID */
    private static final long serialVersionUID = 6720507617603163762L;
    /** The wrapped counter */
    protected final LongCounter counter;
    public Wrapper(final LongCounter counter) {
      this.counter = counter;
    }
    public long increment() {
      return counter.increment();
    }
    public long decrement() {
      return counter.decrement();
    }
    public long getCount() {
      return counter.getCount();
    }
    public void reset() {
      counter.reset();
    }
    public boolean equals(final Object obj) {
      return counter.equals(obj);
    }
    public String toString() {
      return counter.toString();
    }
    public Object clone() {
      return counter.clone();
    }
  }
  /**
   * Return a synchronized counter.
   * 
   * @param counter
   *          LongCounter to synchronize.
   * @return Synchronized counter.
   */
  public static LongCounter makeSynchronized(final LongCounter counter) {
    return new Wrapper(counter) {
      /** The serialVersionUID */
      private static final long serialVersionUID = 8903330696503363758L;
      public synchronized long increment() {
        return this.counter.increment();
      }
      public synchronized long decrement() {
        return this.counter.decrement();
      }
      public synchronized long getCount() {
        return this.counter.getCount();
      }
      public synchronized void reset() {
        this.counter.reset();
      }
      public synchronized int hashCode() {
        return this.counter.hashCode();
      }
      public synchronized boolean equals(final Object obj) {
        return this.counter.equals(obj);
      }
      public synchronized String toString() {
        return this.counter.toString();
      }
      public synchronized Object clone() {
        return this.counter.clone();
      }
    };
  }
  /**
   * Returns a directional counter.
   * 
   * @param counter
   *          LongCounter to make directional.
   * @param increasing
   *          True to create an increasing only or false to create a decreasing
   *          only.
   * @return A directional counter.
   */
  public static LongCounter makeDirectional(final LongCounter counter, final boolean increasing) {
    LongCounter temp;
    if (increasing) {
      temp = new Wrapper(counter) {
        /** The serialVersionUID */
        private static final long serialVersionUID = -8902748795144754375L;
        public long decrement() {
          throw new UnsupportedOperationException();
        }
        public void reset() {
          throw new UnsupportedOperationException();
        }
      };
    } else {
      temp = new Wrapper(counter) {
        /** The serialVersionUID */
        private static final long serialVersionUID = 2584758778978644599L;
        public long increment() {
          throw new UnsupportedOperationException();
        }
      };
    }
    return temp;
  }
}





An integer synchronized counter class.

    
/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.util;
import java.io.Serializable;
/**
 * An integer counter class.
 *
 * @version <tt>$Revision: 2800 $</tt>
 * @author  
 */
public class Counter
   implements Serializable, Cloneable
{
   /** The serialVersionUID */
   private static final long serialVersionUID = 7736259185393081556L;
   /** The current count */
   private int count;
   /**
    * Construct a Counter with a starting value.
    *
    * @param count   Starting value for counter.
    */
   public Counter(final int count) {
      this.count = count;
   }
   /**
    * Construct a Counter.
    */
   public Counter() {}
   /**
    * Increment the counter. (Optional operation)
    *
    * @return  The incremented value of the counter.
    */
   public int increment() {
      return ++count;
   }
   /**
    * Decrement the counter. (Optional operation)
    *
    * @return  The decremented value of the counter.
    */
   public int decrement() {
      return --count;
   }
   /**
    * Return the current value of the counter.
    *
    * @return  The current value of the counter.
    */
   public int getCount() {
      return count;
   }
   /**
    * Reset the counter to zero. (Optional operation)
    */
   public void reset() {
      this.count = 0;
   }
   /**
    * Check if the given object is equal to this.
    *
    * @param obj  Object to test equality with.
    * @return     True if object is equal to this.
    */
   public boolean equals(final Object obj) {
      if (obj == this) return true;
      if (obj != null && obj.getClass() == getClass()) {
         return ((Counter)obj).count == count;
      }
      
      return false;
   }
   /**
    * Return a string representation of this.
    *
    * @return  A string representation of this.
    */
   public String toString() {
      return String.valueOf(count);
   }
   /**
    * Return a cloned copy of this object.
    *
    * @return  A cloned copy of this object.
    */
   public Object clone() {
      try {
         return super.clone();
      }
      catch (CloneNotSupportedException e) {
         throw new InternalError();
      }
   }

   /////////////////////////////////////////////////////////////////////////
   //                                Wrappers                             //
   /////////////////////////////////////////////////////////////////////////
   /**
    * Base wrapper class for other wrappers.
    */
   private static class Wrapper
      extends Counter
   {
      /** The serialVersionUID */
      private static final long serialVersionUID = -1803971437884946242L;
      /** The wrapped counter */
      protected final Counter counter;
      public Wrapper(final Counter counter) {
         this.counter = counter;
      }
      public int increment() {
         return counter.increment();
      }
      public int decrement() {
         return counter.decrement();
      }
      public int getCount() {
         return counter.getCount();
      }
      public void reset() {
         counter.reset();
      }
      public boolean equals(final Object obj) {
         return counter.equals(obj);
      }
      public String toString() {
         return counter.toString();
      }
      public Object clone() {
         return counter.clone();
      }
   }
   /**
    * Return a synchronized counter.
    *
    * @param counter    Counter to synchronize.
    * @return           Synchronized counter.
    */
   public static Counter makeSynchronized(final Counter counter) {
      return new Wrapper(counter) {
            /** The serialVersionUID */
         private static final long serialVersionUID = -6024309396861726945L;
            public synchronized int increment() {
               return this.counter.increment();
            }
            public synchronized int decrement() {
               return this.counter.decrement();
            }
            public synchronized int getCount() {
               return this.counter.getCount();
            }
            public synchronized void reset() {
               this.counter.reset();
            }
            public synchronized int hashCode() {
               return this.counter.hashCode();
            }
            public synchronized boolean equals(final Object obj) {
               return this.counter.equals(obj);
            }
            public synchronized String toString() {
               return this.counter.toString();
            }
            public synchronized Object clone() {
               return this.counter.clone();
            }
         };
   }
   /**
    * Returns a directional counter.
    *
    * @param counter       Counter to make directional.
    * @param increasing    True to create an increasing only
    *                      or false to create a decreasing only.
    * @return              A directional counter.
    */
   public static Counter makeDirectional(final Counter counter,
                                         final boolean increasing)
   {
      Counter temp;
      if (increasing) {
         temp = new Wrapper(counter) {
               /** The serialVersionUID */
            private static final long serialVersionUID = 2161377898611431781L;
               public int decrement() {
                  throw new UnsupportedOperationException();
               }
               public void reset() {
                  throw new UnsupportedOperationException();
               }
            };
      }
      else {
         temp = new Wrapper(counter) {
            /** The serialVersionUID */
            private static final long serialVersionUID = -4683457706354663230L;
               public int increment() {
                  throw new UnsupportedOperationException();
               }
            };
      }
      
      return temp;
   }
}





A simple logging facility.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * --------
 * Log.java
 * --------
 * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner (taquera@sherito.org);
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: Log.java,v 1.5 2006/06/08 17:42:20 taqua Exp $
 *
 * Changes
 * -------
 * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
 * 11-Jun-2003 : Removing LogTarget did not work. 
 * 
 */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
/**
 * A simple logging facility. Create a class implementing the
 * {@link org.jfree.util.LogTarget} interface to use this feature.
 * 
 * @author Thomas Morgner
 */
public class Log {
  /**
   * A simple message class.
   */
  public static class SimpleMessage {
    /**
     * The message.
     */
    private String message;
    /**
     * The parameters.
     */
    private Object[] param;
    /**
     * Creates a new message.
     * 
     * @param message
     *          the message text.
     * @param param1
     *          parameter 1.
     */
    public SimpleMessage(final String message, final Object param1) {
      this.message = message;
      this.param = new Object[] { param1 };
    }
    /**
     * Creates a new message.
     * 
     * @param message
     *          the message text.
     * @param param1
     *          parameter 1.
     * @param param2
     *          parameter 2.
     */
    public SimpleMessage(final String message, final Object param1, final Object param2) {
      this.message = message;
      this.param = new Object[] { param1, param2 };
    }
    /**
     * Creates a new message.
     * 
     * @param message
     *          the message text.
     * @param param1
     *          parameter 1.
     * @param param2
     *          parameter 2.
     * @param param3
     *          parameter 3.
     */
    public SimpleMessage(final String message, final Object param1, final Object param2,
        final Object param3) {
      this.message = message;
      this.param = new Object[] { param1, param2, param3 };
    }
    /**
     * Creates a new message.
     * 
     * @param message
     *          the message text.
     * @param param1
     *          parameter 1.
     * @param param2
     *          parameter 2.
     * @param param3
     *          parameter 3.
     * @param param4
     *          parameter 4.
     */
    public SimpleMessage(final String message, final Object param1, final Object param2,
        final Object param3, final Object param4) {
      this.message = message;
      this.param = new Object[] { param1, param2, param3, param4 };
    }
    /**
     * Creates a new message.
     * 
     * @param message
     *          the message text.
     * @param param
     *          the parameters.
     */
    public SimpleMessage(final String message, final Object[] param) {
      this.message = message;
      this.param = param;
    }
    /**
     * Returns a string representation of the message (useful for debugging).
     * 
     * @return the string.
     */
    public String toString() {
      final StringBuffer b = new StringBuffer();
      b.append(this.message);
      if (this.param != null) {
        for (int i = 0; i < this.param.length; i++) {
          b.append(this.param[i]);
        }
      }
      return b.toString();
    }
  }
  /**
   * The logging threshold.
   */
  private int debuglevel;
  /**
   * Storage for the log targets.
   */
  private LogTarget[] logTargets;
  /** The log contexts. */
  private HashMap logContexts;
  /**
   * the singleton instance of the Log system.
   */
  private static Log singleton;
  /**
   * Creates a new Log instance. The Log is used to manage the log targets.
   */
  protected Log() {
    this.logContexts = new HashMap();
    this.logTargets = new LogTarget[0];
    this.debuglevel = 100;
  }
  /**
   * Returns the singleton Log instance. A new instance is created if necessary.
   * 
   * @return the singleton instance.
   */
  public static synchronized Log getInstance() {
    if (singleton == null) {
      singleton = new Log();
    }
    return singleton;
  }
  /**
   * Redefines or clears the currently used log instance.
   * 
   * @param log
   *          the new log instance or null, to return to the default
   *          implementation.
   */
  protected static synchronized void defineLog(final Log log) {
    singleton = log;
  }
  /**
   * Returns the currently defined debug level. The higher the level, the more
   * details are printed.
   * 
   * @return the debug level.
   */
  public int getDebuglevel() {
    return this.debuglevel;
  }
  /**
   * Defines the debug level for the log system.
   * 
   * @param debuglevel
   *          the new debug level
   * @see #getDebuglevel()
   */
  protected void setDebuglevel(final int debuglevel) {
    this.debuglevel = debuglevel;
  }
  /**
   * Adds a log target to this facility. Log targets get informed, via the
   * LogTarget interface, whenever a message is logged with this class.
   * 
   * @param target
   *          the target.
   */
  public synchronized void addTarget(final LogTarget target) {
    if (target == null) {
      throw new NullPointerException();
    }
    final LogTarget[] data = new LogTarget[this.logTargets.length + 1];
    System.arraycopy(this.logTargets, 0, data, 0, this.logTargets.length);
    data[this.logTargets.length] = target;
    this.logTargets = data;
  }
  /**
   * Removes a log target from this facility.
   * 
   * @param target
   *          the target to remove.
   */
  public synchronized void removeTarget(final LogTarget target) {
    if (target == null) {
      throw new NullPointerException();
    }
    final ArrayList l = new ArrayList();
    l.addAll(Arrays.asList(this.logTargets));
    l.remove(target);
    final LogTarget[] targets = new LogTarget[l.size()];
    this.logTargets = (LogTarget[]) l.toArray(targets);
  }
  /**
   * Returns the registered logtargets.
   * 
   * @return the logtargets.
   */
  public LogTarget[] getTargets() {
    return (LogTarget[]) this.logTargets.clone();
  }
  /**
   * Replaces all log targets by the given target.
   * 
   * @param target
   *          the new and only logtarget.
   */
  public synchronized void replaceTargets(final LogTarget target) {
    if (target == null) {
      throw new NullPointerException();
    }
    this.logTargets = new LogTarget[] { target };
  }
  /**
   * A convenience method for logging a "debug" message.
   * 
   * @param message
   *          the message.
   */
  public static void debug(final Object message) {
    log(LogTarget.DEBUG, message);
  }
  /**
   * A convenience method for logging a "debug" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public static void debug(final Object message, final Exception e) {
    log(LogTarget.DEBUG, message, e);
  }
  /**
   * A convenience method for logging an "info" message.
   * 
   * @param message
   *          the message.
   */
  public static void info(final Object message) {
    log(LogTarget.INFO, message);
  }
  /**
   * A convenience method for logging an "info" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public static void info(final Object message, final Exception e) {
    log(LogTarget.INFO, message, e);
  }
  /**
   * A convenience method for logging a "warning" message.
   * 
   * @param message
   *          the message.
   */
  public static void warn(final Object message) {
    log(LogTarget.WARN, message);
  }
  /**
   * A convenience method for logging a "warning" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public static void warn(final Object message, final Exception e) {
    log(LogTarget.WARN, message, e);
  }
  /**
   * A convenience method for logging an "error" message.
   * 
   * @param message
   *          the message.
   */
  public static void error(final Object message) {
    log(LogTarget.ERROR, message);
  }
  /**
   * A convenience method for logging an "error" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public static void error(final Object message, final Exception e) {
    log(LogTarget.ERROR, message, e);
  }
  /**
   * Logs a message to the main log stream. All attached log targets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done.
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   */
  protected void doLog(int level, final Object message) {
    if (level > 3) {
      level = 3;
    }
    if (level <= this.debuglevel) {
      for (int i = 0; i < this.logTargets.length; i++) {
        final LogTarget t = this.logTargets[i];
        t.log(level, message);
      }
    }
  }
  /**
   * Logs a message to the main log stream. All attached log targets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done.
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   */
  public static void log(final int level, final Object message) {
    getInstance().doLog(level, message);
  }
  /**
   * Logs a message to the main log stream. All attached logTargets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done. <p/> The
   * exception"s stacktrace will be appended to the log-stream
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   * @param e
   *          the exception, which should be logged.
   */
  public static void log(final int level, final Object message, final Exception e) {
    getInstance().doLog(level, message, e);
  }
  /**
   * Logs a message to the main log stream. All attached logTargets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done. <p/> The
   * exception"s stacktrace will be appended to the log-stream
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   * @param e
   *          the exception, which should be logged.
   */
  protected void doLog(int level, final Object message, final Exception e) {
    if (level > 3) {
      level = 3;
    }
    if (level <= this.debuglevel) {
      for (int i = 0; i < this.logTargets.length; i++) {
        final LogTarget t = this.logTargets[i];
        t.log(level, message, e);
      }
    }
  }
  /**
   * Initializes the logging system. Implementors should override this method to
   * supply their own log configuration.
   */
  public void init() {
    // this method is intentionally empty.
  }
  /**
   * Returns true, if the log level allows debug messages to be printed.
   * 
   * @return true, if messages with an log level of DEBUG are allowed.
   */
  public static boolean isDebugEnabled() {
    return getInstance().getDebuglevel() >= LogTarget.DEBUG;
  }
  /**
   * Returns true, if the log level allows informational messages to be printed.
   * 
   * @return true, if messages with an log level of INFO are allowed.
   */
  public static boolean isInfoEnabled() {
    return getInstance().getDebuglevel() >= LogTarget.INFO;
  }
  /**
   * Returns true, if the log level allows warning messages to be printed.
   * 
   * @return true, if messages with an log level of WARN are allowed.
   */
  public static boolean isWarningEnabled() {
    return getInstance().getDebuglevel() >= LogTarget.WARN;
  }
  /**
   * Returns true, if the log level allows error messages to be printed.
   * 
   * @return true, if messages with an log level of ERROR are allowed.
   */
  public static boolean isErrorEnabled() {
    return getInstance().getDebuglevel() >= LogTarget.ERROR;
  }
  /**
   * Creates a log context.
   * 
   * @param context
   *          the class (<code>null</code> not permitted).
   * 
   * @return A log context.
   */
  public static LogContext createContext(final Class context) {
    return createContext(context.getName());
  }
  /**
   * Creates a log context.
   * 
   * @param context
   *          the label for the context.
   * 
   * @return A log context.
   */
  public static LogContext createContext(final String context) {
    return getInstance().internalCreateContext(context);
  }
  /**
   * Creates a log context.
   * 
   * @param context
   *          the name of the logging context (a common prefix).
   * 
   * @return A log context.
   */
  protected LogContext internalCreateContext(final String context) {
    synchronized (this) {
      LogContext ctx = (LogContext) this.logContexts.get(context);
      if (ctx == null) {
        ctx = new LogContext(context);
        this.logContexts.put(context, ctx);
      }
      return ctx;
    }
  }
}
/*
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 * 
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info: http://www.jfree.org/jcommon/index.html
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * 
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. in the
 * United States and other countries.]
 * 
 * -------------- LogTarget.java -------------- (C)opyright 2002-2004, by Object
 * Refinery Limited.
 * 
 * $Id: LogTarget.java,v 1.3 2005/11/14 10:55:59 mungady Exp $
 * 
 * Changes ------- 11-May-2002 : Initial version 06-Dec-2002 : LogTargets now
 * use Object-Parameters instead of Strings. 05-Feb-2003 : Removed unnecessary
 * methods. 29-Apr-2003 : Distilled from the JFreeReport project and moved into
 * JCommon
 * 
 */
/**
 * An interface that defines a log target (a consumer of log messages). Classes
 * which implement this interface can be registered with the
 * {@link org.jfree.util.Log} class and will then receive logging messages
 * generated by the code.
 * 
 * @author Thomas Morgner
 */
interface LogTarget {
  /**
   * Loglevel ERROR.
   */
  public static final int ERROR = 0;
  /**
   * Loglevel WARN.
   */
  public static final int WARN = 1;
  /**
   * Loglevel INFO.
   */
  public static final int INFO = 2;
  /**
   * Loglevel DEBUG.
   */
  public static final int DEBUG = 3;
  /** Strings for the log levels. */
  public static final String[] LEVELS = { "ERROR: ", "WARN:  ", "INFO:  ", "DEBUG: " };
  /**
   * Logs a message at a specified log level.
   * 
   * @param level
   *          the log level.
   * @param message
   *          the log message.
   */
  public void log(int level, Object message);
  /**
   * Logs a message at a specified log level.
   * 
   * @param level
   *          the log level.
   * @param message
   *          the log message.
   * @param e
   *          the exception
   */
  public void log(int level, Object message, Exception e);
}
/*
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 * 
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info: http://www.jfree.org/jcommon/index.html
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * 
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. in the
 * United States and other countries.]
 * 
 * --------------- LogContext.java --------------- (C)opyright 2004, by Thomas
 * Morgner and Contributors.
 * 
 * Original Author: Thomas Morgner; Contributor(s): David Gilbert (for Object
 * Refinery Limited);
 * 
 * $Id: LogContext.java,v 1.3 2005/10/18 13:24:19 mungady Exp $
 * 
 * Changes ------- 26-Apr-2004 : Initial version (TM);
 * 
 */
/**
 * A log context.
 * 
 * @author Thomas Morgner
 */
class LogContext {
  /** The prefix string. */
  private String contextPrefix;
  /**
   * Creates a new log context.
   * 
   * @param contextPrefix
   *          the prefix.
   */
  public LogContext(final String contextPrefix) {
    this.contextPrefix = contextPrefix;
  }
  /**
   * Returns true, if the log level allows debug messages to be printed.
   * 
   * @return true, if messages with an log level of DEBUG are allowed.
   */
  public boolean isDebugEnabled() {
    return Log.isDebugEnabled();
  }
  /**
   * Returns true, if the log level allows informational messages to be printed.
   * 
   * @return true, if messages with an log level of INFO are allowed.
   */
  public boolean isInfoEnabled() {
    return Log.isInfoEnabled();
  }
  /**
   * Returns true, if the log level allows warning messages to be printed.
   * 
   * @return true, if messages with an log level of WARN are allowed.
   */
  public boolean isWarningEnabled() {
    return Log.isWarningEnabled();
  }
  /**
   * Returns true, if the log level allows error messages to be printed.
   * 
   * @return true, if messages with an log level of ERROR are allowed.
   */
  public boolean isErrorEnabled() {
    return Log.isErrorEnabled();
  }
  /**
   * A convenience method for logging a "debug" message.
   * 
   * @param message
   *          the message.
   */
  public void debug(final Object message) {
    log(LogTarget.DEBUG, message);
  }
  /**
   * A convenience method for logging a "debug" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public void debug(final Object message, final Exception e) {
    log(LogTarget.DEBUG, message, e);
  }
  /**
   * A convenience method for logging an "info" message.
   * 
   * @param message
   *          the message.
   */
  public void info(final Object message) {
    log(LogTarget.INFO, message);
  }
  /**
   * A convenience method for logging an "info" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public void info(final Object message, final Exception e) {
    log(LogTarget.INFO, message, e);
  }
  /**
   * A convenience method for logging a "warning" message.
   * 
   * @param message
   *          the message.
   */
  public void warn(final Object message) {
    log(LogTarget.WARN, message);
  }
  /**
   * A convenience method for logging a "warning" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public void warn(final Object message, final Exception e) {
    log(LogTarget.WARN, message, e);
  }
  /**
   * A convenience method for logging an "error" message.
   * 
   * @param message
   *          the message.
   */
  public void error(final Object message) {
    log(LogTarget.ERROR, message);
  }
  /**
   * A convenience method for logging an "error" message.
   * 
   * @param message
   *          the message.
   * @param e
   *          the exception.
   */
  public void error(final Object message, final Exception e) {
    log(LogTarget.ERROR, message, e);
  }
  /**
   * Logs a message to the main log stream. All attached log targets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done.
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   */
  public void log(final int level, final Object message) {
    if (this.contextPrefix != null) {
      Log.getInstance().doLog(level, new Log.SimpleMessage(this.contextPrefix, ":", message));
    } else {
      Log.getInstance().doLog(level, message);
    }
  }
  /**
   * Logs a message to the main log stream. All attached logTargets will also
   * receive this message. If the given log-level is higher than the given
   * debug-level in the main config file, no logging will be done. <p/> The
   * exception"s stacktrace will be appended to the log-stream
   * 
   * @param level
   *          log level of the message.
   * @param message
   *          text to be logged.
   * @param e
   *          the exception, which should be logged.
   */
  public void log(final int level, final Object message, final Exception e) {
    if (this.contextPrefix != null) {
      Log.getInstance().doLog(level, new Log.SimpleMessage(this.contextPrefix, ":", message), e);
    } else {
      Log.getInstance().doLog(level, message, e);
    }
  }
  /**
   * Tests this object for equality with an arbitrary object.
   * 
   * @param o
   *          the object to test against (<code>null</code> permitted).
   * 
   * @return A boolean.
   */
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof LogContext)) {
      return false;
    }
    final LogContext logContext = (LogContext) o;
    if (this.contextPrefix != null) {
      if (!this.contextPrefix.equals(logContext.contextPrefix)) {
        return false;
      }
    } else {
      if (logContext.contextPrefix != null) {
        return false;
      }
    }
    return true;
  }
  /**
   * Returns a hashcode.
   * 
   * @return The hashcode.
   */
  public int hashCode() {
    return (this.contextPrefix != null ? this.contextPrefix.hashCode() : 0);
  }
}





Class providing static methods to log diagnostics

   
// jTDS JDBC Driver for Microsoft SQL Server and Sybase
// Copyright (C) 2004 The jTDS Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
import java.sql.*;
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * Class providing static methods to log diagnostics.
 * <p>
 * There are three ways to enable logging:
 * <ol>
 * <li>Pass a valid PrintWriter to DriverManager.setLogWriter().
 * <li>Pass a valid PrintWriter to DataSource.setLogWriter().
 * <li>For backwards compatibility call Logger.setActive();
 * </ol>
 *
 * @author Mike Hutchinson
 * @version $Id: Logger.java,v 1.11 2005/04/20 16:49:31 alin_sinpalean Exp $
 */
public class Logger {
    /** PrintWriter stream set by DataSource. */
    private static PrintWriter log;
    /**
     * Set the logging PrintWriter stream.
     *
     * @param out the PrintWriter stream
     */
    public static void setLogWriter(PrintWriter out) {
        log = out;
    }
    /**
     * Get the logging PrintWriter Stream.
     *
     * @return the logging stream as a <code>PrintWriter</code>
     */
    public static PrintWriter getLogWriter() {
        return log;
    }
    /**
     * Retrieve the active status of the logger.
     *
     * @return <code>boolean</code> true if logging enabled
     */
    public static boolean isActive() {
        return(log != null || DriverManager.getLogWriter() != null);
    }
    /**
     * Print a diagnostic message to the output stream provided by
     * the DataSource or the DriverManager.
     *
     * @param message the diagnostic message to print
     */
    public static void println(String message) {
        if (log != null) {
            log.println(message);
        } else {
            DriverManager.println(message);
        }
    }
    private static final char hex[] =
    {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
    /**
     * Print a dump of the current input or output network packet.
     *
     * @param streamId the owner of this packet
     * @param in       true if this is an input packet
     * @param pkt      the packet data
     */
    public static void logPacket(int streamId, boolean in, byte[] pkt) {
        int len = ((pkt[2] & 0xFF) << 8)| (pkt[3] & 0xFF);
        StringBuffer line = new StringBuffer(80);
        line.append("----- Stream #");
        line.append(streamId);
        line.append(in ? " read" : " send");
        line.append((pkt[1] != 0) ? " last " : " ");
        switch (pkt[0]) {
            case 1:
                line.append("Request packet ");
                break;
            case 2:
                line.append("Login packet ");
                break;
            case 3:
                line.append("RPC packet ");
                break;
            case 4:
                line.append("Reply packet ");
                break;
            case 6:
                line.append("Cancel packet ");
                break;
            case 14:
                line.append("XA control packet ");
                break;
            case 15:
                line.append("TDS5 Request packet ");
                break;
            case 16:
                line.append("MS Login packet ");
                break;
            case 17:
                line.append("NTLM Authentication packet ");
                break;
            case 18:
                line.append("MS Prelogin packet ");
                break;
            default:
                line.append("Invalid packet ");
                break;
        }
        println(line.toString());
        println("");
        line.setLength(0);
        for (int i = 0; i < len; i += 16) {
            if (i < 1000) {
                line.append(" ");
            }
            if (i < 100) {
                line.append(" ");
            }
            if (i < 10) {
                line.append(" ");
            }
            line.append(i);
            line.append(":").append(" ");
            int j = 0;
            for (; j < 16 && i + j < len; j++) {
                int val = pkt[i+j] & 0xFF;
                line.append(hex[val >> 4]);
                line.append(hex[val & 0x0F]);
                line.append(" ");
            }
            for (; j < 16 ; j++) {
                line.append("   ");
            }
            line.append("|");
            for (j = 0; j < 16 && i + j < len; j++) {
                int val = pkt[i + j] & 0xFF;
                if (val > 31 && val < 127) {
                    line.append((char) val);
                } else {
                    line.append(" ");
                }
            }
            line.append("|");
            println(line.toString());
            line.setLength(0);
        }
        println("");
    }
    /**
     * Print an Exception stack trace to the log.
     *
     * @param e the exception to log
     */
    public static void logException(Exception e) {
        if (log != null) {
            e.printStackTrace(log);
        } else if (DriverManager.getLogWriter() != null) {
            e.printStackTrace(DriverManager.getLogWriter());
        }
    }
    //
    // Backward compatbility method
    //
    /**
     * Turn the logging on or off.
     *
     * @deprecated Use the JDBC standard mechanisms to enable logging.
     * @param value  true to turn on logging
     */
    public static void setActive(boolean value) {
        if (value && log == null) {
            try {
                log = new PrintWriter(new FileOutputStream("log.out"), true);
            } catch (IOException e) {
                log = null; // Sorry no logging!
            }
        }
    }
}





Counts down from a specified value the number of bytes actually read from the wrapped InputStream.

  
 
/* Copyright (c) 2001-2009, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.IOException;
import java.io.InputStream;
/**
 * Counts down from a specified value the number of bytes actually read
 * from the wrapped InputStream. <p>
 *
 * Returns minus one (-1) early from readXXX methods if the count
 * down reaches zero (0) before the end of the wrapped InputStream
 * is encountered. <p>
 *
 * This class is especially useful when a fixed number of bytes is to be read
 * from an InputStream that is in turn to be used as the source for an
 * {@link java.io.InputStreamReader InputStreamReader}.
 *
 * @author boucherb@users
 * @version 1.8.x
 * @since 1.8.x
 */
public final class CountdownInputStream extends InputStream {
    private long        count;
    private InputStream input;
    public CountdownInputStream(final InputStream is) {
        this.input = is;
    }
    public int read() throws IOException {
        if (this.count <= 0) {
            return -1;
        }
        final int b = this.input.read();
        if (b >= 0) {
            this.count--;
        }
        return b;
    }
    public int read(final byte[] buf) throws IOException {
        if (this.count <= 0) {
            return -1;
        }
        int len = buf.length;
        if (len > this.count) {
            len = (int) this.count;
        }
        final int r = this.input.read(buf, 0, len);
        if (r > 0) {
            this.count -= r;
        }
        return r;
    }
    public int read(final byte[] buf, final int off,
                    int len) throws IOException {
        if (this.count <= 0) {
            return -1;
        }
        if (len > this.count) {
            len = (int) this.count;
        }
        final int r = this.input.read(buf, 0, len);
        if (r > 0) {
            this.count -= r;
        }
        return r;
    }
    public void close() throws IOException {
        this.input.close();
    }
    public long getCount() {
        return this.count;
    }
    public void setCount(long count) {
        this.count = count;
    }
}





Debugging utility that reports, in a brute force manner, any internal data of a class instance

   
//----------------------------------------------------------------------------//
//                                                                            //
//                                D u m p e r                                 //
//                                                                            //
//  Copyright (C) Herve Bitteur 2000-2009. All rights reserved.               //
//  This software is released under the GNU General Public License.           //
//  Please contact users@audiveris.dev.java.net to report bugs & suggestions. //
//----------------------------------------------------------------------------//
//
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
/**
 * Class <code>Dumper</code> is a debugging utility that reports, in a brute
 * force manner, any internal data of a class instance.
 *
 * <p> When used on a class instance, all class internal fields which are
 * considered as "relevant" are printed using their toString() method, then we
 * walk up the inheritance tree and repeat the same actions, until there is no
 * more superclass or until the superclass we have reached is considered as
 * non-relevant. </p>
 *
 * <p> A (super)class is considered "relevant" if the static method
 * <code>isClassRelevant(class)</code> returns true. This method can be
 * overridden in a subclass of Dumper to adapt to local needs. </p>
 *
 * <p> A field is considered "relevant" if the following condition if the method
 * <code>isFieldRelevant(field)</code> returns true. Similarly, the behavior of
 * this predicate can be customized by subclassing the Dumper class. </p>
 *
 * <p> There are several kinds of print outs available through subclassing. Each
 * of them export two public methods: <code>dump()</code> which prints the
 * result on default output stream, and <code>dumpOf()</code> which simply
 * returns the generated dump string.
 *
 * <ul> <li> <b>Column</b> a dump with one line per field </li>
 *
 * <li> <b>Row</b> a dump with all information on one row </li>
 *
 * <li> <b>Html</b> an Html stream with fields arranged in tables </li>
 *
 * </ul>
 *
 * Here are some examples of use:
 * <pre>
 * // Using the predefined static helper methods
 * Dumper.dump(myinstance);
 * Dumper.dump(myinstance, "My Title");
 * Dumper.dump(myinstance, "My Title", 2);
 * System.out.println(Dumper.dumpOf(myinstance));
 * System.out.println(Dumper.htmlDumpOf(myinstance));
 *
 *  // Using directly the Dumper subclasses
 * new Dumper.Column(myinstance).print();
 * System.out.println(new Dumper.Row(myinstance).toString());
 * display(new Dumper.Html(myinstance).toString());
 * </pre>
 *
 * @author Herv&eacute; Bitteur
 * @version $Id: Dumper.java,v 1.15 2009/03/03 19:45:51 hbitteur Exp $
 */
public abstract class Dumper
{
    //~ Instance fields --------------------------------------------------------
    /**
     * The object to be dumped
     */
    protected final Object obj;
    /**
     * The string buffer used as output
     */
    protected final StringBuffer sb;
    /**
     * Can we use HTML directives?
     */
    protected final boolean useHtml;
    /** Maximum number of collection items printed */
    private final int MAX_COLLECTION_INDEX = 9;
    /**
     * Class (beware, this variable is updated as we walk up the inheritance
     * tree)
     */
    protected Class cl;
    //~ Constructors -----------------------------------------------------------
    /**
     * Creates a new Dumper.
     *
     * @param obj the object instance to be dumped.
     */
    private Dumper (Object  obj,
                    boolean useHtml)
    {
        // (re)Allocate the string buffer
        sb = new StringBuffer(1024);
        // Cache the object & the related class
        this.obj = obj;
        this.useHtml = useHtml;
        cl = obj.getClass();
    }
    //~ Methods ----------------------------------------------------------------
    //-----------------//
    // isClassRelevant //
    //-----------------//
    /**
     * Predicate to determine if a given class is worth being printed. This
     * method could be overridden to reflect customized policy. Note that when
     * walking up the inheritance tree, the browsing is stopped as soon as a
     * non-relevant class is encountered.
     *
     * @param cl the class at stake
     *
     * @return true if found relevant
     */
    public static boolean isClassRelevant (Class cl)
    {
        //        return (cl != null) && !cl.getName()
        //                                  .startsWith("java.") &&
        //               !cl.getName()
        //                  .startsWith("javax.");
        return (cl != null) && cl.getName()
                                 .startsWith("omr.");
    }
    //-----------------//
    // isFieldRelevant //
    //-----------------//
    /**
     * Predicate to determine if a given field is worth being printed. This
     * method could be overridden to reflect customized policy.
     *
     * @param field the field at stake
     *
     * @return true if found relevant
     */
    public static boolean isFieldRelevant (Field field)
    {
        // We don"t print static field since the Dumper is meant for instances
        if (Modifier.isStatic(field.getModifiers())) {
            return false;
        }
        // We don"t print non-user visible entities
        if (field.getName()
                 .indexOf("$") != -1) {
            return false;
        }
        return true;
    }
    //------//
    // dump //
    //------//
    /**
     * Helper function that prints the internal data of an object onto the
     * standard output.
     *
     * @param obj the instance to dump
     */
    public static void dump (Object obj)
    {
        dump(obj, null, 0);
    }
    //------//
    // dump //
    //------//
    /**
     * Helper function that prints the internal data of an object onto the
     * standard output, with a specified left indentation level.
     *
     * @param obj   the instance to dump
     * @param level the indentation level (0 means no indentation)
     */
    public static void dump (Object obj,
                             int    level)
    {
        dump(obj, null, level);
    }
    //------//
    // dump //
    //------//
    /**
     * Helper function that prints the internal data of an object onto the
     * standard output, with the ability to print a related title
     *
     * @param obj   the object to dump
     * @param title the title to print beforehand
     */
    public static void dump (Object obj,
                             String title)
    {
        dump(obj, title, 0);
    }
    //------//
    // dump //
    //------//
    /**
     * Helper function that prints the internal data of an object onto the
     * standard output, with room for a title and left indentation.
     *
     * @param obj   the object to dump
     * @param title the title to print beforehand
     * @param level the indentation level (0 for no indent)
     */
    public static void dump (Object obj,
                             String title,
                             int    level)
    {
        new Column(obj, title, level).print();
    }
    //--------//
    // dumpOf //
    //--------//
    /**
     * Helper function that returns a line which contains the whole set of
     * internal data
     *
     * @param obj the object whose data is to be printed
     *
     * @return the string of data values
     */
    public static String dumpOf (Object obj)
    {
        return new Row(obj).toString();
    }
    //------------//
    // htmlDumpOf //
    //------------//
    /**
     * Helper function that prints a special kind of information string, using
     * HTML tags so that an html editor can easily render this.
     *
     * @param obj the object to dump
     *
     * @return the HTML string
     */
    public static String htmlDumpOf (Object obj)
    {
        return new Html(obj).toString();
    }
    //-------//
    // print //
    //-------//
    /**
     * Print the dump string onto the standard output
     */
    public void print ()
    {
        System.out.println(toString());
    }
    //----------//
    // toString //
    //----------//
    /**
     * Return the string buffer content
     *
     * @return the dump of the object as a string
     */
    @Override
    public String toString ()
    {
        // Do the processing
        processObject();
        // Return the final content of string buffer
        return sb.toString();
    }
    //------------------//
    // printClassEpilog //
    //------------------//
    /**
     * To be overridden so as to print the epilog of class data
     */
    protected void printClassEpilog ()
    {
    }
    //------------------//
    // printClassProlog //
    //------------------//
    /**
     * To be overridden so as to print the prolog of class data
     */
    protected void printClassProlog ()
    {
    }
    //----------------------//
    // printCollectionValue //
    //----------------------//
    protected void printCollectionValue (Collection col)
    {
        sb.append("[");
        int i = 0;
        for (Object obj : col) {
            if (i++ > 0) {
                sb.append(useHtml ? ",<br/>" : ",");
            }
            // Safeguard action when the object is a big collection
            if (i > MAX_COLLECTION_INDEX) {
                sb.append(" ... " + col.size() + " items");
                break;
            } else {
                sb.append(obj);
            }
        }
        sb.append("]");
    }
    //------------//
    // printField //
    //------------//
    /**
     * Basic printing of field name and value. The method can of course be
     * overridden.
     *
     * @param name  the field name
     * @param value the field value, which may be null
     */
    protected void printField (String name,
                               Object value)
    {
        if (value == null) {
            sb.append("null");
        } else {
            if (value instanceof Collection) {
                printCollectionValue((Collection) value);
            } else if (value instanceof Map) {
                printCollectionValue(((Map) value).entrySet());
            } else {
                sb.append(value.toString());
            }
        }
    }
    //--------------//
    // processClass //
    //--------------//
    private void processClass ()
    {
        // Class Prolog
        printClassProlog();
        // Process the class Fields
        for (Field field : cl.getDeclaredFields()) {
            processField(field);
        }
        // Class Epilog
        printClassEpilog();
    }
    //--------------//
    // processField //
    //--------------//
    private void processField (Field field)
    {
        // Check that we are really interested in printing this field out
        if (isFieldRelevant(field)) {
            // Override any access limitation
            field.setAccessible(true);
            try {
                // Retrieve field value in the object instance
                Object value = field.get(obj);
                // Print the field value as requested
                printField(field.getName(), value);
            } catch (IllegalAccessException ex) {
                // Cannot occur in fact, thanks to setAccessible
            }
        }
    }
    //---------------//
    // processObject //
    //---------------//
    private void processObject ()
    {
        do {
            // Process the class at hand
            processClass();
            // Walk up the inheritance tree
            cl = cl.getSuperclass();
        } while (isClassRelevant(cl));
    }
    //~ Inner Classes ----------------------------------------------------------
    //--------//
    // Column //
    //--------//
    /**
     * Class <code>Column</code> implements a Dumper where all fields are
     * presented in one column, each field on a separate line. The column can be
     * left indented, according to the specified indentation level.
     */
    public static class Column
        extends Dumper
    {
        //~ Static fields/initializers -----------------------------------------
        private static final String MEMBER_GAP = "   ";
        private static final String INDENT_GAP = ".  ";
        //~ Instance fields ----------------------------------------------------
        private final String       title;
        private final StringBuffer prefix;
        //~ Constructors -------------------------------------------------------
        public Column (Object obj,
                       String title,
                       int    level)
        {
            super(obj, false);
            // Cache the title
            if (title != null) {
                this.title = title;
            } else {
                this.title = "";
            }
            // Prepare indent prefix
            prefix = new StringBuffer(level * INDENT_GAP.length());
            for (int i = level; i > 0; i--) {
                prefix.append(INDENT_GAP);
            }
        }
        //~ Methods ------------------------------------------------------------
        @Override
        protected void printClassProlog ()
        {
            // We print the class name only for the lowest class in
            // heritance hierarchy
            if (obj.getClass() == cl) {
                sb.append("\n");
                sb.append(prefix)
                  .append(cl.getName());
                sb.append(" ")
                  .append(title)
                  .append(":");
            }
        }
        @Override
        protected void printField (String name,
                                   Object value)
        {
            sb.append("\n");
            sb.append(prefix)
              .append(MEMBER_GAP);
            sb.append(name)
              .append("=");
            super.printField(name, value);
        }
    }
    //------//
    // Html //
    //------//
    /**
     * Class <code>Html</code> implements a Dumper using HTML tags to present
     * fields in a table.
     */
    public static class Html
        extends Dumper
    {
        //~ Constructors -------------------------------------------------------
        protected Html (Object obj)
        {
            super(obj, true);
        }
        //~ Methods ------------------------------------------------------------
        @Override
        public String toString ()
        {
            // Style
            sb.append("<style> td {")
              .append(" font-family: Lucida Console, Verdana, sans-serif;")
              .append(" font-size: 9px;")
              .append(" font-style: normal;")
              .append("} </style>");
            // Table begin
            sb.append("<table border=0 cellpadding=3>");
            // The object
            super.processObject();
            // Table end
            sb.append("</table>");
            // Return the final content of string buffer
            return sb.toString();
        }
        @Override
        protected void printClassProlog ()
        {
            // Class name
            sb.append("<tr><td colspan=2><font color="BLUE">")
              .append(cl.getName())
              .append("</font></td></tr>");
        }
        @Override
        protected void printField (String name,
                                   Object value)
        {
            // One table row per field
            sb.append("<tr>");
            // First the field name
            sb.append("<td align="right"><font color="RED">")
              .append(name)
              .append("</font></td>");
            // Then the field value
            sb.append("<td>");
            super.printField(name, value);
            sb.append("</td>")
              .append("</tr>");
        }
    }
    //-----//
    // Row //
    //-----//
    /**
     * Class <code>Row</code> implements a Dumper where all fields are presented
     * on the same line.
     */
    public static class Row
        extends Dumper
    {
        //~ Constructors -------------------------------------------------------
        protected Row (Object obj)
        {
            super(obj, false);
        }
        //~ Methods ------------------------------------------------------------
        @Override
        protected void printClassEpilog ()
        {
            sb.append("}");
        }
        @Override
        protected void printClassProlog ()
        {
            // Class name
            sb.append("{");
            // Special annotation for superclass
            if (obj.getClass() != cl) {
                sb.append("from ");
            }
            sb.append(cl.getName())
              .append(":");
        }
        @Override
        protected void printField (String name,
                                   Object value)
        {
            sb.append(" ");
            sb.append(name)
              .append("=");
            super.printField(name, value);
        }
    }
}





Debug InputStream

   
/*
Copyright (C) 2004  Juho V&auml;h&auml;-Herttua
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
02111-1307, USA.
*/

import java.io.*;
public class DebugInputStream extends InputStream {
  InputStream is;
  ByteArrayOutputStream buffer;
  boolean debug;
  public DebugInputStream(InputStream in, boolean usedebug) {
    is = in;
    buffer = new ByteArrayOutputStream();
    debug = usedebug;
  }
  public int read() throws IOException {
    int input;
    input = is.read();
    if (debug) buffer.write(input);
    return input;
  }
  public int read(byte b[], int off, int len) throws IOException {
    int readb;
    readb = is.read(b, off, len);
    if (debug) buffer.write(b, off, readb);
    return readb;
  }
  public int available() throws IOException {
    return is.available();
  }
  public void close() throws IOException {
    buffer.close();
    is.close();
  }
  public void mark(int readlimit) {
    is.mark(readlimit);
  }
  public void reset() throws IOException {
    is.reset();
  }
  public boolean markSupported() {
    return is.markSupported();
  }

  public byte[] toByteArray() {
    return buffer.toByteArray();
  }
  public int size() {
    return buffer.size();
  }
}





Debug Utilities

   
/*
 ** Copyright (c) 1998 by Timothy Gerard Endres
 ** <mailto:time@ice.ru>  <http://www.ice.ru>
 ** 
 ** This program is free software.
 ** 
 ** You may redistribute it and/or modify it under the terms of the GNU
 ** General Public License as published by the Free Software Foundation.
 ** Version 2 of the license should be included with this distribution in
 ** the file LICENSE, as well as License.html. If the license is not
 ** included with this distribution, you may find a copy at the FSF web
 ** site at "www.gnu.org" or "www.fsf.org", or you may write to the
 ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
 **
 ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
 ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
 ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
 ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
 ** REDISTRIBUTION OF THIS SOFTWARE. 
 ** 
 */
import java.io.PrintWriter;
public class DebugUtilities {
  public static void printClassHierarchy(Class aClass, PrintWriter writer, String prefix) {
    String subPrefix = "-->";
    for (int i = 0;; ++i) {
      writer.println(prefix + " " + subPrefix + " " + aClass.getName());
      aClass = aClass.getSuperclass();
      if (aClass == Object.class)
        break;
      subPrefix = "--" + subPrefix;
    }
  }
  public static void printContainerComponents(java.awt.Container cont, PrintWriter writer,
      String prefix, boolean recurse) {
    java.awt.ruponent[] comps = cont.getComponents();
    if (comps.length < 1) {
      writer.println(prefix + "Contains no components.");
    }
    for (int i = 0; i < comps.length; ++i) {
      DebugUtilities.printClassHierarchy(comps[i].getClass(), writer, prefix + "[" + i + "]");
      if (recurse) {
        Class c = java.awt.Container.class;
        if (c.isAssignableFrom(comps[i].getClass())) {
          DebugUtilities.printContainerComponents((java.awt.Container) comps[i], writer, (prefix
              + "[" + i + "] "), recurse);
        }
      }
    }
  }
}





Debug Utility

  
/*
 * Copyright (c) 1998-2002 Carnegie Mellon University.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS"" AND
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public abstract class Debug {
    public static final Debug VERBOSE = new Verbose ();
    public static final Debug QUIET = new Quiet ();
    public static final Debug NONE = new NoDebug ();
    public static Debug getDebugLevel (Class cls)
        throws NoSuchFieldException {
        try {
            Field fld = cls.getField ("debug");
            if (fld.getType () != Debug.class
                || !Modifier.isStatic (fld.getModifiers ()))
                throw new NoSuchFieldException ();
            return (Debug) fld.get (null);
        } catch (IllegalArgumentException e) {
            throw new NoSuchFieldException ();
        } catch (IllegalAccessException e) {
            throw new NoSuchFieldException ();
        } catch (SecurityException e) {
            throw new NoSuchFieldException ();
        }
    }
    public static void setDebugLevel (Class cls, Debug level) 
        throws NoSuchFieldException {
        try {
            Field fld = cls.getField ("debug");
            if (fld.getType () != Debug.class
                || !Modifier.isStatic (fld.getModifiers ()))
                throw new NoSuchFieldException ();
            fld.set (null, level);
        } catch (IllegalArgumentException e) {
            throw new NoSuchFieldException ();
        } catch (IllegalAccessException e) {
            throw new NoSuchFieldException ();
        } catch (SecurityException e) {
            throw new NoSuchFieldException ();
        }
    }
    public abstract boolean isEnabled ();
    public abstract void print (String message);
    public abstract void println (String message);
    public abstract void print (Object obj);
    public abstract void println (Object obj);
    public abstract void report (Throwable t);
    public abstract void printThreadInfo ();
    public abstract void printStackTrace ();
    public abstract void assertion (boolean f);
    public static class Verbose extends Debug { 
        protected PrintStream out;
        public Verbose () {
            this (System.err);
        }
        public Verbose (PrintStream out) {
            this.out = out;
        }
        public boolean isEnabled () {
            return true;
        }
        public void print (String message) {
            out.print (message);
            out.flush ();
        }
        public void println (String message) {
            out.println (message);
            out.flush ();
        }
        public void print (Object obj) {
            print (obj.toString ());
        }
        public void println (Object obj) {
            println (obj.toString ());
        }
        public void report (Throwable t) {
            t.printStackTrace (out);
            out.flush ();
        }
        public void printThreadInfo () {
            ThreadGroup g = Thread.currentThread().getThreadGroup ();
            Thread[] t = new Thread[g.activeCount ()];
            g.enumerate (t);
            out.println ("Active threads in " + g);
            for (int i=0; i<t.length; ++i)
                out.println (t[i]);
            out.flush ();
        }
        public void printStackTrace () {
            try {
                throw new Exception ();
            } catch (Exception e) {
                e.printStackTrace (out);
                out.flush ();
            }
        }
        public void assertion (boolean f) {
            if (!f)
                throw new RuntimeException ("assertion failure");
        }
    }
    public static class Quiet extends Verbose { 
        public Quiet () {
        }
        public Quiet (PrintStream out) {
            super (out);
        }
        public boolean isEnabled () {
            return false;
        }
        public void print (String message) {
        }
        public void println (String message) {
        }
        public void print (Object message) {
        }
        public void println (Object message) {
        }
        public void report (Throwable t) {
            t.printStackTrace (out);
            out.flush ();
        }
        public void printThreadInfo () {
        }
        public void printStackTrace () {
        }
        public void assertion (boolean f) {
            if (!f) {
                try {
                    throw new RuntimeException ("assertion failure");
                } catch (RuntimeException e) {
                    e.printStackTrace (out);
                    out.flush ();
                }
            }
        }
    }
    public static class NoDebug extends Debug { 
        public boolean isEnabled () {
            return false;
        }
        public void print (String message) {
        }
        public void println (String message) {
        }
        public void print (Object message) {
        }
        public void println (Object message) {
        }
        public void report (Throwable t) {
        }
        public void printThreadInfo () {
        }
        public void printStackTrace () {
        }
        public void assertion (boolean f) {
        }
    }
}





Handle obtaining string timestamps

  
/**
 *  Copyright 2007 University Of Southern California
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * Create a common interface to handle obtaining string timestamps.
 * The difficult part is to allow for an ISO 8601 date formatting.
 *
 * @author Jens-S. V&ouml;ckler
 * @author Yong Zhao
 * @version $Revision: 379 $
 *
 * @see java.util.Date
 * @see java.text.SimpleDateFormat
 */
public class Currently {
  /**
   * This is used to format the time stamp.
   */
  private SimpleDateFormat m_formatter = null;
  /**
   * Default time format, which is compact and has a timezone
   */
  public static final String DEFAULT_FORMAT = "yyyy.MM.dd HH:mm:ss zzz";
  /**
   * Default ctor: Create a new instance with a default formatting
   * string for timestamps.
   */
  public Currently() {
    m_formatter = new SimpleDateFormat(DEFAULT_FORMAT);
  }
  /**
   * Ctor: Create a new instance with a formatting string for time stamps.
   * @param formatString complies to {@link java.text.SimpleDateFormat}.
   */
  public Currently(String formatString) {
    m_formatter = new SimpleDateFormat(formatString);
  }
  /**
   * Ctor: Create a new instance with a formatting string for time stamps.
   * @param format is a description of the simple date format to use.
   */
  public Currently(SimpleDateFormat format) {
    m_formatter = (SimpleDateFormat) format.clone();
  }
  /**
   * Accessor: Obtains the default timestamp format for all queues.
   *
   * @return the currently active timestamp prefix format.
   * @see #setDateFormat( String )
   * @see #setDateFormat( SimpleDateFormat )
   */
  public SimpleDateFormat getDateFormat() {
    return m_formatter;
  }
  /**
   * Accessor: Sets the default timestamp format for all queues.
   *
   * @param format is the new timestamp prefix format.
   * @see #setDateFormat( SimpleDateFormat )
   * @see #getDateFormat()
   */
  public void setDateFormat(SimpleDateFormat format) {
    if (format != null) {
      m_formatter = format;
    }
  }
  /**
   * Accessor: Sets the default timestamp format for all queues.
   *
   * @param format is the new timestamp prefix format as a string.
   * @see #setDateFormat( String )
   * @see #getDateFormat()
   */
  public void setDateFormat(String format) {
    if (format != null) {
      m_formatter = new SimpleDateFormat(format);
    }
  }
  /**
   * Obtains the current time as formatted string according to
   * the format option.
   * @return the current time as formatted string.
   * @see #now( Date )
   */
  public String now() {
    return this.now(new Date());
  }
  /**
   * Obtains the current time as formatted string according to
   * the format option.
   * @param then is a timestamp expressed as Date.
   * @return the current time as formatted string.
   * @see #now()
   */
  public String now(Date then) {
    return this.m_formatter.format(then);
  }
  /**
   * Store the regular expressions necessary to parse ISO timestamps.
   */
  private static final String c_expression[] = {
      "([12][0-9]{3})-([01][0-9])-([0123][0-9])(T([012][0-9]):([0-6][0-9]):([0-6][0-9])?(\\.[0-9]+)?)?(Z|[-+][01][0-9]:?[0-6][0-9])?",
      "([12][0-9]{3})([01][0-9])([0123][0-9])(T?([012][0-9])([0-6][0-9])([0-6][0-9])?(\\.[0-9]+)?)?(Z|[-+][01][0-9]:?[0-6][0-9])?"
  };
  /**
   * Stores compiled patterns at first use, quasi-Singleton.
   */
  private static Pattern c_pattern[] = null;
  /**
   * Parses one of the ISO 8601 that it produces. Note, it will not
   * parse the full range of ISO timestamps.
   *
   * @param stamp is the textual timestamp representation.
   * @return a time or <code>null</code>, if unparsable.
   */
  public static Date parse(String stamp) {
    // initialize the compiled expressions once
    if (c_pattern == null) {
      c_pattern = new Pattern[c_expression.length];
      for (int i = 0; i < c_expression.length; ++i) {
        c_pattern[i] = Pattern.rupile(c_expression[i]);
      }
    }
    // match against pattern
    for (int i = 0; i < c_expression.length; ++i) {
      Matcher m = c_pattern[i].matcher(stamp);
      if (m.matches()) {
        Calendar c = Calendar.getInstance();
        TimeZone z = TimeZone.getDefault();
        if (m.group(9) != null && m.group(9).length() > 0) {
          boolean utc = (Character.toUpperCase(m.group(9).charAt(0)) == "Z");
          if (utc) {
            z = TimeZone.getTimeZone("GMT+0");
          } else {
            z = TimeZone.getTimeZone("GMT" + m.group(9));
          }
        }
        c.setTimeZone(z);
        c.set(Calendar.YEAR, Integer.parseInt(m.group(1)));
        c.set(Calendar.MONTH,
              Integer.parseInt(m.group(2)) + (Calendar.JANUARY - 1));
        c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(3)));
        if (m.group(4).length() > 0) {
          c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(5)));
          c.set(Calendar.MINUTE, Integer.parseInt(m.group(6)));
          if (m.group(7) != null && m.group(7).length() > 0) {
            c.set(Calendar.SECOND, Integer.parseInt(m.group(7)));
          }
          if (m.group(8) != null && m.group(8).length() > 1) {
            String millis = m.group(8).substring(1);
            while (millis.length() < 3) {
              millis += "0";
            }
            millis = millis.substring(0, 3);
            c.set(Calendar.MILLISECOND, Integer.parseInt(millis));
          }
        }
        return c.getTime();
      }
    }
    // not found
    return null;
  }
  /**
   * Ignores any internal date format, and tries to show a complete
   * date/timp stamp of the current time in extended ISO 8601 format.
   * UTC time (Zulu time) or a local timezone will be used. A sample for
   * UTC output is 2002-04-23T02:49:58Z   A sample for local zone
   * (CDT) is 2002-04-22T21:49:58-05:00
   *
   * @param zuluTime returns a UTC formatted stamp, if true. Otherwise
   * the time will be formatted according to the local zone.
   * @return an ISO 8601 formatted date and time representation for the
   * current time in extended format without millisecond resolution
   * @see #iso8601( boolean, boolean, boolean, Date )
   */
  public static String iso8601(boolean zuluTime) {
    return Currently.iso8601(zuluTime, true, false, new Date());
  }
  /**
   * Ignores any internal date format, and tries to show a complete
   * date/timp stamp in extended ISO 8601 format. UTC time (Zulu time)
   * or a local timezone will be used.<p>
   *
   * <table border=1>
   * <tr><th>zone</th><th>format</th><th>fraction</td><th>example</th></tr>
   * <tr><td>local</td><td>basic</td><td>integral</td><td>20020523T140427-0500</td></tr>
   * <tr><td>UTC</td><td>basic</td><td>integral</td><td>20020523190427Z</td></tr>
   * <tr><td>local</td><td>extd.</td><td>integral</td><td>2002-05-23T14:04:27-05:00</td></tr>
   * <tr><td>UTC</td><td>extd.</td><td>integral</td><td>2002-05-23T19:04:27Z</td></tr>
   * <tr><td>local</td><td>basic</td><td>millis</td><td>20020523T140427.166-0500</td></tr>
   * <tr><td>UTC</td><td>basic</td><td>millis</td><td>20020523190427.166Z</td></tr>
   * <tr><td>local</td><td>extd.</td><td>millis</td><td>2002-05-23T14:04:27.166-05:00</td></tr>
   * <tr><td>UTC</td><td>extd.</td><td>millis</td><td>2002-05-23T19:04:27.166Z</td></tr>
   * </table><p>
   *
   * @param zuluTime returns a UTC formatted stamp, if true. Otherwise
   * the time will be formatted according to the local zone. Local time
   * should be prefixed with the "T".
   * @param extendedFormat will use the extended ISO 8601 format which
   * separates the different timestamp items. If false, the basic
   * format will be used. In UTC and basic format, the "T" separator
   * will be omitted.
   * @param withMillis will put the millisecond extension into the timestamp.
   * If false, the time will be without millisecond fraction. The separator
   * is taken from {@link java.text.DecimalFormatSymbols#getMinusSign()},
   * which usually is a period or a comma.
   * @param now is a time stamp as Date.
   * @return an ISO 8601 formatted date and time representation for
   * the given point in time.
   */
  public static String iso8601(boolean zuluTime, boolean extendedFormat,
                               boolean withMillis, Date now) {
    Calendar c =
        Calendar.getInstance(zuluTime ?
                             TimeZone.getTimeZone("UTC") :
                             TimeZone.getDefault());
    c.setTime(now);
    // set up formattting options
    DecimalFormat nf2 = new DecimalFormat("##00");
    DecimalFormat nf3 = new DecimalFormat("###000");
    DecimalFormat nf4 = new DecimalFormat("####0000");
    DecimalFormatSymbols dfs = nf2.getDecimalFormatSymbols();
    // allocate result string buffer
    int size = extendedFormat ? (zuluTime ? 25 : 30) : (zuluTime ? 21 : 25);
    if (!withMillis) {
      size -= 4;
    }
    StringBuffer result = new StringBuffer(size);
    result.append(nf4.format(c.get(Calendar.YEAR)));
    if (extendedFormat) {
      result.append("-"); // position 5
    }
    result.append(nf2.format(c.get(Calendar.MONTH) + 1));
    if (extendedFormat) {
      result.append("-"); // position 8
    }
    result.append(nf2.format(c.get(Calendar.DAY_OF_MONTH)));
    // generating UTC in basic format may leave out the "T" separator
    if (extendedFormat || !zuluTime) {
      result.append("T"); // position 11
    }
    result.append(nf2.format(c.get(Calendar.HOUR_OF_DAY)));
    if (extendedFormat) {
      result.append(":"); // position 14
    }
    result.append(nf2.format(c.get(Calendar.MINUTE)));
    if (extendedFormat) {
      result.append(":"); // position 17
    }
    result.append(nf2.format(c.get(Calendar.SECOND)));
    if (withMillis) {
      // Though there is no explicit spec which allows a complete
      // timestamp with milliseconds, it is implied through two
      // levels, sigh. 5.3.4.2 allows decimal fractions with
      // time-only stamps that have a timezone. The intro of 5.4.2
      // allows 5.3.1.3.
      result.append(dfs.getDecimalSeparator()); // position 20
      result.append(nf3.format(c.get(Calendar.MILLISECOND)));
    }
    if (zuluTime) {
      // this is easy
      result.append("Z");
    } else {
      // time zone calculations
      int zone_offset = c.get(Calendar.ZONE_OFFSET) / 1000;
      int save_offset = c.get(Calendar.DST_OFFSET) / 1000;
      int diff = (zone_offset + save_offset) / 60;
      result.append(diff < 0 ? dfs.getMinusSign() : "+"); // position 24
      if (diff < 0) {
        diff = Math.abs(diff);
      }
      result.append(nf2.format(diff / 60));
      if (extendedFormat) {
        result.append(":");
      }
      result.append(nf2.format(diff % 60));
    }
    return result.toString();
  }
}





How to do Benchmark

    
/*
 * Copyright (c) 1996, 1997 by Doug Bell <dbell@shvn.ru>.  All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Label;
import java.awt.List;
import java.awt.TextArea;
public class BenchmarkApplet extends java.applet.Applet
  implements BenchmarkRunner, Runnable
{
  static final String spaces =
              "                                                       ";
  static final String newline = System.getProperty("line.separator");
  private volatile boolean  running;
  private int         estimatatedSeconds;
  private ThreadGroup     tgroup;
  private Thread        testTask;
  private List        testList;
  private TextArea      out;
  private Label       timeEstimate;
  private Button        doit, abort, clear;
  private Checkbox      console;
  private Benchmark[]     tests = {
                  new Benchmark(this),
                  new MixedBenchmark(this),
                  new LoopBenchmark(this),
                  new VariableBenchmark(this),
                  new MethodBenchmark(this),
                  new OperatorBenchmark(this),
                  new CastingBenchmark(this),
                  new InstantiationBenchmark(this),
                  new ExceptionBenchmark(this)
                };

  public void init () {
    tgroup = Thread.currentThread().getThreadGroup();
    Font    font = new Font("Courier", Font.PLAIN, 10);
    FontMetrics fm = getFontMetrics(font);
    int     lines = Math.max(10, size().height / fm.getHeight() - 4);
    out = new TextArea(lines, spaces.length() + Benchmark.resolutionName.length());
    out.setFont(font);
    out.setEditable(false);
    add(out);
    boolean toobig;
    do {
      testList = new List(--lines, true);
      add(testList, 0);
      validate();
      if (toobig = testList.size().height - out.size().height > 2)
        remove(testList);
    } while (toobig);
    for (int ii = 0;  ii < tests.length;  ii++)
      testList.addItem(tests[ii].getName());
    testList.select(0);   // Calibration benchmark
    testList.select(1);   // Mixed benchmark
    timeEstimate = new Label(getTimeEstimate());
    add(timeEstimate);
    add(doit  = new Button("Run Benchmark"));
    add(abort = new Button("Stop"));
    add(clear = new Button("Clear"));
    abort.disable();
    clear.disable();
    add(console = new Checkbox("Console"));
    validate();
  }

  public void start () {
    Benchmark.recalibrate();
  }

  public synchronized void run () {
    try {
      running = true;
      timingTests();
    }
    finally {
      running = false;
      doit.enable();
      abort.disable();
    }
  }

  public boolean action (Event evt, Object arg) {
    if (evt.target == doit) {
      if (!running) {
        testTask = new Thread(tgroup, this);
        testTask.start();
      }
      return true;
    }
    else if (evt.target == abort) {
      if (running) {
        testTask.stop();
        println("*** aborted by user ***");
      }
      return true;
    }
    else if (evt.target == clear) {
      out.setText("");
      clear.disable();
      return true;
    }
    return false;
  }

  public boolean handleEvent (Event evt) {
    if (evt.target == testList) {
      if (evt.id == Event.LIST_SELECT  ||  evt.id == Event.LIST_DESELECT)
        if (timeEstimate != null)
          timeEstimate.setText(getTimeEstimate());
    }
    return super.handleEvent(evt);
  }

  private void timingTests () {
    int   cnt, testSeconds = 0;
    long  begin = System.currentTimeMillis();
    doit.disable();
    abort.enable();
    Benchmark.gc();
    println(newline +
        "Benchmark tests:  [mem=" + Runtime.getRuntime().freeMemory() +"/" +
                      Runtime.getRuntime().totalMemory() +"]");
    for (cnt = 0;  cnt < testList.countItems();  cnt++)
      if (testList.isSelected(cnt))
        testSeconds += tests[cnt].getTestTime();
    println("Estimated time: " + timeString(estimatatedSeconds) + " (tests " +
        timeString(testSeconds) + ")");
    long total = 0;
    for (cnt = 0;  cnt < testList.countItems();  cnt++)
      if (testList.isSelected(cnt))
        total += tests[cnt].runTest();
    println("*** done: " +
        timeString((int) (System.currentTimeMillis() + 500 - begin) / 1000) +
        " (tests " +
        timeString((int) ((total + 500) / 1000)) +
        ") ***");
  }

  static String timeString (int seconds) {
    int sec = seconds % 60;
    return (seconds / 60) + ((sec < 10) ? ":0" : ":") + sec;
  }
  private String getTimeEstimate () {
    estimatatedSeconds = 0;
    for (int cnt = 0;  cnt < testList.countItems();  cnt++)
      if (testList.isSelected(cnt))
        estimatatedSeconds += tests[cnt].getRunningTime();
    return "Estimated running time: " + timeString(estimatatedSeconds);
  }

  public void report (String msg, long nanos) {
    if (msg != null) {
      String  time = Long.toString(nanos);
      int   index = msg.length() + time.length();
      String  space = (index >= spaces.length()) ? " " : spaces.substring(index);
      println(msg + space + time + Benchmark.resolutionName);
    }
  }
  public synchronized void println (String s) {
    if (console.getState())
      System.out.println(s);
    out.appendText(s + newline);
    clear.enable();
    Thread.yield();  // give interface a chance to process events
  }
}  // class BenchmarkApplet
// EOF

/*
 * Copyright (c) 1996, 1997 by Doug Bell <dbell@shvn.ru>.  All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

class DerivedObject {}
class DerivedObject2 extends DerivedObject {}
class DerivedObject3 extends DerivedObject2 {}
class DerivedObject4 extends DerivedObject3 {}
class DerivedObject5 extends DerivedObject4 {}
interface Inter1 {}
interface Inter2 extends Inter1 {}
interface Inter3 extends Inter2 {}
interface Inter4 extends Inter3 {}
interface Inter5 extends Inter4 {}
interface Inter6 extends Inter5 {}

/*
 * This is the base benchmark class.  To create a new benchmark, extend this class and
 * implement getTestTime(), getRunningTime() and runTest() in the extended class.
 */
 class Benchmark implements Runnable {
  private static boolean    calibrated;
  private static long     gcMemTarget;
  private static String[]   resNames = {" ms", " �s", " ns", " ps"};
  private static long[]   resValues = {1000L, 1000000L, 1000000000L, 1000000000000L};
  protected static int    resIndex = 2;   // ns = nanosecond
  protected static String   resolutionName = resNames[resIndex];
  protected static long   resolution = resValues[resIndex];
  protected static long   timerLoopNanos;
  protected static int[]    useint = new int[3]; // used to prevent dead variable elimination
  private BenchmarkRunner   runner;
  private Thread        timer;
  private long        sampleMillis = 1000L; // 1 second for each test
  private int         sampleCount = 3;
  private int         timerIterations;
  private boolean       timerPaused;
  private long        timerStart, reportMillis;
  private int[]       iterations = new int[sampleCount];
  private long[]        milliseconds = new long[sampleCount];
  protected long        timerMillis, totalMillis;
  protected volatile boolean  go;

  public static void gc () {
    System.runFinalization();
    System.gc();
    if (Runtime.getRuntime().freeMemory() < gcMemTarget) {
      try {
        int[] mem = new int[(int) gcMemTarget/4];
        mem = null;
      }
      catch (OutOfMemoryError e) {
        gcMemTarget -= 10000;
        recalibrate();
      }
      System.gc();
    }
    try { Thread.sleep(100); } catch (InterruptedException e) {}
  }

  public static void recalibrate () {
    calibrated = false;
  }

  public static void calibrate () {
    calibrated = false;
    new Benchmark().runTest();
    if (timerLoopNanos < 98) {
      if (resIndex < resValues.length - 1) {
        resIndex++;
        resolutionName = resNames[resIndex];
        resolution = resValues[resIndex];
        calibrate();
      }
    }
    else if (timerLoopNanos > 102000) {
      if (resIndex > 0) {
        resIndex--;
        resolutionName = resNames[resIndex];
        resolution = resValues[resIndex];
        calibrate();
      }
    }
    if (!calibrated) {
      gcMemTarget = 0;
      gc();
      long sysmem = Math.min(1000000, Runtime.getRuntime().totalMemory() - 10000);
      gcMemTarget = Math.min(1000000, Runtime.getRuntime().freeMemory() - 5000);
      if (true|| gcMemTarget < 200000  &&  sysmem > gcMemTarget) {
        boolean ok;
        gcMemTarget = sysmem;
        do {
          ok = true;
          try {
            int[] mem = new int[(int) gcMemTarget/4];
            mem = null;
          }
          catch (OutOfMemoryError e) {
            gcMemTarget -= 10000;
            ok = false;
          }
        } while (!ok);
      }
      gcMemTarget = Math.min(sysmem, gcMemTarget);
      calibrated = true;
    }
  }

  static long getNanos (long[] millis, int[] iterations, long overheadNanos) {
    long nanos = resolution * 100;
    for (int ii = Math.min(millis.length, iterations.length);  --ii >= 0; ) {
      if (iterations[ii] > 0)
        nanos = Math.min(nanos,
                 (((resolution/1000) * millis[ii]) / iterations[ii]) -
                  overheadNanos);
      iterations[ii] = 0;
      millis[ii] = 0;
    }
    return nanos;
  }

  Benchmark () {
    this(null);
  }
  Benchmark (BenchmarkRunner runner) {
    this.runner = runner;
  }

  /** Returns the name of the test.
   *  Default implementation uses the unqualified class name, stripping "Benchmark"
   *  from the name if it exists.
   */
  public String getName () {
    String name = getClass().getName();
    int index = name.lastIndexOf(".");
    name = name.substring(index < 0 ? 0 : index);
    if (name.equals("Benchmark"))
      name = "Calibrate";
    else if (name.endsWith("Benchmark"))
      name = name.substring(0, name.length() - "Benchmark".length());
    return name;
  }

  /** Returns approximate running time of justs the timing tests, in seconds.
   *  Subclass should override this method.
   */
  public int getTestTime () {
    return (int) (getSampleCount() * getSampleMillis()) / 1000;
  }

  /** Returns approximate total running time of the benchmark, in seconds.
   *  Subclass should override this method.
   */
  public int getRunningTime () {
    return getTestTime();
  }

  /** Set the number of samples to measure for a test.
   */
  final void setSampleCount (int samples) {
    if (samples != sampleCount  &&  samples > 0) {
      sampleCount = samples;
      iterations = new int[samples];
      milliseconds = new long[samples];
    }
  }
  /** Get the number of samples to measure for a test.
   */
  final int getSampleCount () {
    return sampleCount;
  }

  /** Set the number of milliseconds to run the timer.
   */
  final void setSampleMillis (long millis) {
    if (millis > 0)
      sampleMillis = millis;
  }
  /** Get the number of milliseconds to run the timer.
   */
  final long getSampleMillis () {
    return sampleMillis;
  }

  /** Should be called at the beginning of runTest().
   */
  protected void startTest () {
    println("");
    println("





Logging class to record errors or unexpected behavior to a file

  
/*BEGIN_COPYRIGHT_BLOCK
 *
 * Copyright (c) 2001-2008, JavaPLT group at Rice University (drjava@rice.edu)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software is Open Source Initiative approved Open Source Software.
 * Open Source Initative Approved is a trademark of the Open Source Initiative.
 * 
 * This file is part of DrJava.  Download the current version of this project
 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 * 
 * END_COPYRIGHT_BLOCK*/

import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
/** Logging class to record errors or unexpected behavior to a file.  The file is created in the current directory,
  * and is only used if the log is enabled.  All logs can be enabled at once with the ENABLE_ALL field.
  * @version $Id: Log.java 4691 2008-12-02 23:33:27Z dlsmith $
  */
public class Log {
  public static final boolean ENABLE_ALL = false;
  
  /** Whether this particular log is enabled in development mode. */
  protected volatile boolean _isEnabled;
  
  /** The filename of this log. */
  protected volatile String _name;
  
  /** The file object for this log. */
  protected volatile File _file;
  
  /** PrintWriter to print messages to a file. */
  protected volatile PrintWriter _writer;
  
  public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("d MMM yyyy H:mm:ss z");
  static {
    DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
    DATE_FORMAT.setLenient(false);
  }
  
  /** Creates a new Log with the given name.  If enabled is true, a file is created in the current directory with the
    * given name.
    * @param name  File name for the log
    * @param isEnabled  Whether to actively use this log
    */
  public Log(String name, boolean isEnabled) { this(new File(name), isEnabled); }
  
  public Log(File f, boolean isEnabled) {
    _file = f;
    _name = f.getName();
    _isEnabled = isEnabled;
    _init();
  }
  
  /** Creates the log file, if enabled. */
  protected void _init() {
    if (_writer == null) {
      if (_isEnabled || ENABLE_ALL) {
        try {
          FileWriter w = new FileWriter(_file.getAbsolutePath(), true);
          _writer = new PrintWriter(w);
          log("Log "" + _name + "" opened: " + DATE_FORMAT.format(new Date()));
        }
        catch (IOException ioe) {
          throw new RuntimeException("Could not create log: " + ioe);
        }
      }
    }
  }
  
  /** Sets whether this log is enabled.  Only has an effect if the code is in development mode.
    * @param isEnabled  Whether to print messages to the log file
    */
  public void setEnabled(boolean isEnabled) { _isEnabled = isEnabled; }
  
  /** Returns whether this log is currently enabled. */
  public boolean isEnabled() { return (_isEnabled || ENABLE_ALL); }
  
  /** Prints a message to the log, if enabled.
    * @param message Message to print.
    */
  public synchronized void log(String message) {
    if (isEnabled()) {
      if (_writer == null) {
        _init();
      }
      _writer.println(DATE_FORMAT.format(new Date()) + ": " + message);
      _writer.flush();
    }
  }
  
  /** Converts a stack trace (StackTraceElement[]) to string form */
  public static String traceToString(StackTraceElement[] trace) {
    final StringBuilder traceImage = new StringBuilder();
    for (StackTraceElement e: trace) traceImage.append("\n\tat " + e.toString());
    return traceImage.toString();
  }
  
  /** Prints a message and exception stack trace to the log, if enabled.
    * @param s  Message to print
    * @param trace  Stack track to log
    */
  public synchronized void log(String s, StackTraceElement[] trace) {
    if (isEnabled()) log(s + traceToString(trace));
  }
  
  /** Prints a message and exception stack trace to the log, if enabled.
    * @param s Message to print
    * @param t Throwable to log
    */
  public synchronized void log(String s, Throwable t) {
    if (isEnabled()) {
      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter(sw);
      t.printStackTrace(pw);
      log(s + "\n" + sw.toString());
    }
  }
  
  /** Closes a log file. */
  public void close() {
    _writer.close();
    _writer = null;
  }
}





Methods for logging events

    
/*
 * Log.java - A class for logging events
 * :tabSize=8:indentSize=8:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Copyright (C) 1999, 2003 Slava Pestov
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//{{{ Imports
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Writer;
import java.text.DateFormat;
import java.util.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import static java.text.DateFormat.MEDIUM;
//}}}
/**
 * This class provides methods for logging events. In terms of functionality,
 * it is somewhere in between <code>System.out.println()</code> and
 * full-blown logging packages such as log4j.<p>
 *
 * All events are logged to an in-memory buffer and optionally a stream,
 * and those with a high urgency (warnings and errors) are also printed
 * to standard output.<p>
 *
 * Logging of exception tracebacks is supported.<p>
 *
 * This class can also optionally redirect standard output and error to the log.
 *
 * @author Slava Pestov
 * @version $Id: Log.java 12789 2008-06-04 21:23:10Z kpouer $
 */
public class Log
{
  //{{{ Constants
  /**
   * The maximum number of log messages that will be kept in memory.
   * @since jEdit 2.6pre5
   */
  public static final int MAXLINES = 500;
  /**
   * Debugging message urgency. Should be used for messages only
   * useful when debugging a problem.
   * @since jEdit 2.2pre2
   */
  public static final int DEBUG = 1;
  /**
   * Message urgency. Should be used for messages which give more
   * detail than notices.
   * @since jEdit 2.2pre2
   */
  public static final int MESSAGE = 3;
  /**
   * Notice urgency. Should be used for messages that directly
   * affect the user.
   * @since jEdit 2.2pre2
   */
  public static final int NOTICE = 5;
  /**
   * Warning urgency. Should be used for messages that warrant
   * attention.
   * @since jEdit 2.2pre2
   */
  public static final int WARNING = 7;
  /**
   * Error urgency. Should be used for messages that signal a
   * failure.
   * @since jEdit 2.2pre2
   */
  public static final int ERROR = 9;
  //}}}
  //{{{ init() method
  /**
   * Initializes the log.
   * @param stdio If true, standard output and error will be
   * sent to the log
   * @param level Messages with this log level or higher will
   * be printed to the system console
   * @since jEdit 3.2pre4
   */
  public static void init(boolean stdio, int level)
  {
    if(stdio)
    {
      if(System.out == realOut && System.err == realErr)
      {
        System.setOut(createPrintStream(NOTICE,null));
        System.setErr(createPrintStream(ERROR,null));
      }
    }
    Log.level = level;
    // Log some stuff
    log(MESSAGE,Log.class,"When reporting bugs, please"
      + " include the following information:");
    String[] props = {
      "java.version", "java.vm.version", "java.runtime.version",
      "java.vendor", "java.rupiler", "os.name", "os.version",
      "os.arch", "user.home", "java.home",
      "java.class.path",
      };
    for(int i = 0; i < props.length; i++)
    {
      log(MESSAGE,Log.class,
        props[i] + "=" + System.getProperty(props[i]));
    }
  } //}}}
  //{{{ setLogWriter() method
  /**
   * Writes all currently logged messages to this stream if there was no
   * stream set previously, and sets the stream to write future log
   * messages to.
   * @param stream The writer
   * @since jEdit 3.2pre4
   */
  public static void setLogWriter(Writer stream)
  {
    if(Log.stream == null && stream != null)
    {
      try
      {
        if(wrap)
        {
          for(int i = logLineCount; i < log.length; i++)
          {
            stream.write(log[i]);
            stream.write(lineSep);
          }
        }
        for(int i = 0; i < logLineCount; i++)
        {
          stream.write(log[i]);
          stream.write(lineSep);
        }
        stream.flush();
      }
      catch(Exception e)
      {
        // do nothing, who cares
      }
    }
    Log.stream = stream;
  } //}}}
  //{{{ flushStream() method
  /**
   * Flushes the log stream.
   * @since jEdit 2.6pre5
   */
  public static void flushStream()
  {
    if(stream != null)
    {
      try
      {
        stream.flush();
      }
      catch(IOException io)
      {
        io.printStackTrace(realErr);
      }
    }
  } //}}}
  //{{{ closeStream() method
  /**
   * Closes the log stream. Should be done before your program exits.
   * @since jEdit 2.6pre5
   */
  public static void closeStream()
  {
    if(stream != null)
    {
      try
      {
        stream.close();
        stream = null;
      }
      catch(IOException io)
      {
        io.printStackTrace(realErr);
      }
    }
  } //}}}
  //{{{ getLogListModel() method
  /**
   * Returns the list model for viewing the log contents.
   * @since jEdit 4.2pre1
   */
  public static ListModel getLogListModel()
  {
    return listModel;
  } //}}}
  //{{{ log() method
  /**
   * Logs an exception with a message.
   *
   * If an exception is the cause of a call to {@link #log}, then
   * the exception should be explicitly provided so that it can
   * be presented to the (debugging) user in a useful manner
   * (not just the exception message, but also the exception stack trace)
   *
   * @since jEdit 4.3pre5
   */
  public static void log(int urgency, Object source, Object message,
    Throwable exception)
  {
    // We can do nicer here, but this is a start...
    log(urgency,source,message);
    log(urgency,source,exception);
  } //}}}
  //{{{ log() method
  /**
   * Logs a message. This method is thread-safe.<p>
   *
   * The following code sends a typical debugging message to the activity
   * log:
   * <pre>Log.log(Log.DEBUG,this,"counter = " + counter);</pre>
   * The corresponding activity log entry might read as follows:
   * <pre>[debug] JavaParser: counter = 15</pre>
   *
   * @param urgency The urgency; can be one of
   * <code>Log.DEBUG</code>, <code>Log.MESSAGE</code>,
   * <code>Log.NOTICE</code>, <code>Log.WARNING</code>, or
   * <code>Log.ERROR</code>.
   * @param source The source of the message, either an object or a
   * class instance. When writing log messages from macros, set
   * this parameter to <code>BeanShell.class</code> to make macro
   * errors easier to spot in the activity log.
   * @param message The message. This can either be a string or
   * an exception
   *
   * @since jEdit 2.2pre2
   */
  public static void log(int urgency, Object source, Object message)
  {
    String _source;
    if(source == null)
    {
      _source = Thread.currentThread().getName();
      if(_source == null)
      {
        _source = Thread.currentThread().getClass().getName();
      }
    }
    else if(source instanceof Class)
      _source = ((Class)source).getName();
    else
      _source = source.getClass().getName();
    int index = _source.lastIndexOf(".");
    if(index != -1)
      _source = _source.substring(index+1);
    if(message instanceof Throwable)
    {
      _logException(urgency,source,(Throwable)message);
    }
    else
    {
      String _message = String.valueOf(message);
      // If multiple threads log stuff, we don"t want
      // the output to get mixed up
      synchronized(LOCK)
      {
        StringTokenizer st = new StringTokenizer(
          _message,"\r\n");
        int lineCount = 0;
        boolean oldWrap = wrap;
        while(st.hasMoreTokens())
        {
          lineCount++;
          _log(urgency,_source,st.nextToken()
            .replace("\t"," "));
        }
        listModel.update(lineCount,oldWrap);
      }
    }
  } //}}}
  //{{{ Private members
  //{{{ Instance variables
  private static final Object LOCK;
  private static final String[] log;
  private static int logLineCount;
  private static boolean wrap;
  private static int level;
  private static Writer stream;
  private static final String lineSep;
  private static final PrintStream realOut;
  private static final PrintStream realErr;
  private static final LogListModel listModel;
  private static final DateFormat timeFormat;
  private static final int MAX_THROWABLES = 10;
  public static final List<Throwable> throwables;
  //}}}
  //{{{ Class initializer
  static
  {
    LOCK = new Object();
    level = WARNING;
    realOut = System.out;
    realErr = System.err;
    log = new String[MAXLINES];
    lineSep = System.getProperty("line.separator");
    listModel = new LogListModel();
    
    timeFormat = DateFormat.getTimeInstance(MEDIUM);
    throwables = Collections.synchronizedList(new ArrayList<Throwable>(MAX_THROWABLES));
  } //}}}
  //{{{ createPrintStream() method
  private static PrintStream createPrintStream(final int urgency,
    final Object source)
  {
    return new LogPrintStream(urgency, source);
  } //}}}
  //{{{ _logException() method
  private static void _logException(final int urgency,
    final Object source,
    final Throwable message)
  {
    PrintStream out = createPrintStream(urgency,source);
    if (urgency >= level)
    {
      synchronized (throwables)
      {
        if (throwables.size() == MAX_THROWABLES)
        {
          throwables.remove(0);
        }
        throwables.add(message);
      }
    }
    synchronized(LOCK)
    {
      message.printStackTrace(out);
    }
  } //}}}
  //{{{ _log() method
  private static void _log(int urgency, String source, String message)
  {
    String fullMessage = timeFormat.format(new Date()) + " ["+Thread.currentThread().getName()+"] [" + urgencyToString(urgency) + "] " + source
      + ": " + message;
    try
    {
      log[logLineCount] = fullMessage;
      if(++logLineCount >= log.length)
      {
        wrap = true;
        logLineCount = 0;
      }
      if(stream != null)
      {
        stream.write(fullMessage);
        stream.write(lineSep);
      }
    }
    catch(Exception e)
    {
      e.printStackTrace(realErr);
    }
    if(urgency >= level)
    {
      if(urgency == ERROR)
        realErr.println(fullMessage);
      else
        realOut.println(fullMessage);
    }
  } //}}}
  //{{{ urgencyToString() method
  private static String urgencyToString(int urgency)
  {
    switch(urgency)
    {
    case DEBUG:
      return "debug";
    case MESSAGE:
      return "message";
    case NOTICE:
      return "notice";
    case WARNING:
      return "warning";
    case ERROR:
      return "error";
    }
    throw new IllegalArgumentException("Invalid urgency: " + urgency);
  } //}}}
  //}}}
  //{{{ LogListModel class
  static class LogListModel implements ListModel
  {
    final List<ListDataListener> listeners = new ArrayList<ListDataListener>();
    //{{{ fireIntervalAdded() method
    private void fireIntervalAdded(int index1, int index2)
    {
      for(int i = 0; i < listeners.size(); i++)
      {
        ListDataListener listener = listeners.get(i);
        listener.intervalAdded(new ListDataEvent(this,
          ListDataEvent.INTERVAL_ADDED,
          index1,index2));
      }
    } //}}}
    //{{{ fireIntervalRemoved() method
    private void fireIntervalRemoved(int index1, int index2)
    {
      for(int i = 0; i < listeners.size(); i++)
      {
        ListDataListener listener = listeners.get(i);
        listener.intervalRemoved(new ListDataEvent(this,
          ListDataEvent.INTERVAL_REMOVED,
          index1,index2));
      }
    } //}}}
    //{{{ addListDataListener() method
    public void addListDataListener(ListDataListener listener)
    {
      listeners.add(listener);
    } //}}}
    //{{{ removeListDataListener() method
    public void removeListDataListener(ListDataListener listener)
    {
      listeners.remove(listener);
    } //}}}
    //{{{ getElementAt() method
    public Object getElementAt(int index)
    {
      if(wrap)
      {
        if(index < MAXLINES - logLineCount)
          return log[index + logLineCount];
        else
          return log[index - MAXLINES + logLineCount];
      }
      else
        return log[index];
    } //}}}
    //{{{ getSize() method
    public int getSize()
    {
      if(wrap)
        return MAXLINES;
      else
        return logLineCount;
    } //}}}
    //{{{ update() method
    void update(final int lineCount, final boolean oldWrap)
    {
      if(lineCount == 0 || listeners.isEmpty())
        return;
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          if(wrap)
          {
            if(oldWrap)
              fireIntervalRemoved(0,lineCount - 1);
            else
            {
              fireIntervalRemoved(0,
                logLineCount);
            }
            fireIntervalAdded(
              MAXLINES - lineCount + 1,
              MAXLINES);
          }
          else
          {
            fireIntervalAdded(
              logLineCount - lineCount + 1,
              logLineCount);
          }
        }
      });
    } //}}}
  } //}}}
  //{{{ LogPrintStream class
  /**
   * A print stream that uses the "Log" class to output the messages,
   * and has special treatment for the printf() function. Using this
   * stream has one caveat: printing messages that don"t have a line
   * break at the end will have one added automatically...
   */
  private static class LogPrintStream extends PrintStream {
    private final ByteArrayOutputStream buffer;
    private final OutputStream orig;
    //{{{ LogPrintStream constructor
    LogPrintStream(int urgency, Object source)
    {
      super(new LogOutputStream(urgency, source));
      buffer = new ByteArrayOutputStream();
      orig = out;
    } //}}}
    //{{{ printf() method
    /**
     * This is a hack to allow "printf" to not print weird
     * stuff to the output. Since "printf" doesn"t seem to
     * print the whole message in one shot, our output
     * stream above would break a line of log into several
     * lines; so we buffer the result of the printf call and
     * print the whole thing in one shot. A similar hack
     * would be needed for the "other" printf method, but
     * I"ll settle for the common case only.
     */
    public PrintStream printf(String format, Object... args)
    {
      synchronized (orig)
      {
        buffer.reset();
        out = buffer;
        super.printf(format, args);
        try
        {
          byte[] data = buffer.toByteArray();
          orig.write(data, 0, data.length);
          out = orig;
        }
        catch (IOException ioe)
        {
          // don"t do anything?
        }
        finally
        {
          buffer.reset();
        }
      }
      return this;
    } //}}}
  } //}}}
  //{{{ LogOutputStream class
  private static class LogOutputStream extends OutputStream
  {
    private final int   urgency;
    private final Object  source;
    //{{{ LogOutputStream constructor
    LogOutputStream(int urgency, Object source)
    {
      this.urgency  = urgency;
      this.source   = source;
    } //}}}
    //{{{ write() method
    public synchronized void write(int b)
    {
      byte[] barray = { (byte)b };
      write(barray,0,1);
    } //}}}
    //{{{ write() method
    public synchronized void write(byte[] b, int off, int len)
    {
      String str = new String(b,off,len);
      log(urgency,source,str);
    } //}}}
  } //}}}
}





Methods for printing Debug messages

   
/*
*  (c) Copyright 2003 Christian Lorenz  ALL RIGHTS RESERVED.
* 
* This file is part of the JavaBluetooth Stack.
* 
* The JavaBluetooth Stack is free software; you can redistribute it 
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* 
* The JavaBluetooth Stack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* Created on May 22, 2003
* by Christian Lorenz
*
*/

/** 
 * This class contains methods for printing Debug messages. Which messages are printed may be changed by adjusting the
 * DEBUGLEVELMIN and DEBUGLEVELMAX variables. Care should be taken when prining large byte arrays, as this
 * will ususally kill the TINI.
 * @author Christian Lorenz
 */
public class Debug {
    public static boolean debugMessages   = true;
    public static final int DEBUGLEVELMIN = 1;
    public static final int DEBUGLEVELMAX = 10;
    public static void println(int level, String label, byte[] packet) {
        if ((level >= DEBUGLEVELMIN) && (level <= DEBUGLEVELMAX)) {
            for (int i = 0; i < packet.length; i++)
                label += " " + Integer.toString((packet[i] & 0xff) + 0x100, 16).substring(1);
            System.err.println(label);
        }
    }
    public static void println(int level, String debugMessage) {
        if ((level >= DEBUGLEVELMIN) && (level <= DEBUGLEVELMAX)) { System.err.println(debugMessage); }
    }
    public static String printByteArray(byte[] packetData) {
        String output = "";
        for (int i = 0; i < packetData.length; i++)
            output += " " + Integer.toString((packetData[i] & 0xff) + 0x100, 16).substring(1);
        return output;
    }
}





Printing indented text

   
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.PrintWriter;
/**
 * A helper class for printing indented text
 *
 * @version $Revision: 1.2 $
 */
public class IndentPrinter {
    private int indentLevel;
    private String indent;
    private PrintWriter out;
    public IndentPrinter() {
        this(new PrintWriter(System.out), "  ");
    }
    public IndentPrinter(PrintWriter out) {
        this(out, "  ");
    }
    public IndentPrinter(PrintWriter out, String indent) {
        this.out = out;
        this.indent = indent;
    }
    public void println(Object value) {
        out.print(value.toString());
        out.println();
    }
    public void println(String text) {
        out.print(text);
        out.println();
    }
    public void print(String text) {
        out.print(text);
    }
    public void printIndent() {
        for (int i = 0; i < indentLevel; i++) {
            out.print(indent);
        }
    }
    public void println() {
        out.println();
    }
    public void incrementIndent() {
        ++indentLevel;
    }
    public void decrementIndent() {
        --indentLevel;
    }
    public int getIndentLevel() {
        return indentLevel;
    }
    public void setIndentLevel(int indentLevel) {
        this.indentLevel = indentLevel;
    }
    public void flush() {
        out.flush();
    }
}





Prints messages formatted for a specific line width.

   
/*
 * $RCSfile: MsgPrinter.java,v $
 * $Revision: 1.1 $
 * $Date: 2005/02/11 05:02:26 $
 * $State: Exp $
 *
 * Class:                   MsgPrinter
 *
 * Description:             Prints messages formatted for a specific
 *                          line width.
 *
 *
 *
 * COPYRIGHT:
 *
 * This software module was originally developed by Rapha&euml;l Grosbois and
 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
 * Askel&ouml;f (Ericsson Radio Systems AB); and Bertrand Berthelot, David
 * Bouchard, F&eacute;lix Henry, Gerard Mozelle and Patrice Onno (Canon Research
 * Centre France S.A) in the course of development of the JPEG2000
 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
 * software module is an implementation of a part of the JPEG 2000
 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
 * Partners) agree not to assert against ISO/IEC and users of the JPEG
 * 2000 Standard (Users) any of their rights under the copyright, not
 * including other intellectual property rights, for this software module
 * with respect to the usage by ISO/IEC and Users of this software module
 * or modifications thereof for use in hardware or software products
 * claiming conformance to the JPEG 2000 Standard. Those intending to use
 * this software module in hardware or software products are advised that
 * their use may infringe existing patents. The original developers of
 * this software module, JJ2000 Partners and ISO/IEC assume no liability
 * for use of this software module or modifications thereof. No license
 * or right to this software module is granted for non JPEG 2000 Standard
 * conforming products. JJ2000 Partners have full right to use this
 * software module for his/her own purpose, assign or donate this
 * software module to any third party and to inhibit third parties from
 * using this software module for non JPEG 2000 Standard conforming
 * products. This copyright notice must be included in all copies or
 * derivative works of this software module.
 *
 * Copyright (c) 1999/2000 JJ2000 Partners.
 *
 *
 *
 */


import java.io.*;
/**
 * This utility class formats messages to the specified line width, by
 * inserting line-breaks between words, and printing the resulting
 * lines.
 * */
public class MsgPrinter {
    /** The line width to use */
    public int lw;
    /** Signals that a newline was found */
    private static final int IS_NEWLINE = -2;
    /** Signals that the end-of-string was reached */
    private static final int IS_EOS = -1;
    /**
     * Creates a new message printer with the specified line width and
     * with the default locale.
     *
     * @param linewidth The line width for which to format (in
     * characters)
     *
     *
     * */
    public MsgPrinter(int linewidth) {
        lw = linewidth;
    }
    /**
     * Returns the line width that is used for formatting.
     *
     * @return The line width used for formatting
     *
     *
     * */
    public int getLineWidth() {
        return lw;
    }
    /**
     * Sets the line width to the specified value. This new value will
     * be used in subsequent calls to the print() message.
     *
     * @param linewidth The new line width to use (in cahracters)
     *
     *
     * */
    public void setLineWidth(int linewidth) {
        if (linewidth <1) {
            throw new IllegalArgumentException();
        }
        lw = linewidth;
    }
    /**
     * Formats the message to print in the current line width, by
     * breaking the message into lines between words. The number of
     * spaces to indent the first line is specified by "flind" and the
     * number of spaces to indent each of the following lines is
     * specified by "ind". Newlines in "msg" are respected. A newline is
     * always printed at the end.
     *
     * @param out Where to print the message.
     *
     * @param flind The indentation for the first line.
     *
     * @param ind The indentation for the other lines.
     *
     * @param msg The message to format and print.
     *
     *
     * */
    public void print(PrintWriter out, int flind, int ind,
                      String msg) {
        int start,end,pend,efflw,lind,i;
        start = 0;
        end = 0;
        pend = 0;
        efflw = lw-flind;
        lind = flind;
        while ((end = nextLineEnd(msg,pend)) != IS_EOS) {
            if (end == IS_NEWLINE) { // Forced line break
                for (i=0; i<lind; i++) {
                    out.print(" ");
                }
                out.println(msg.substring(start,pend));
                if (nextWord(msg,pend) == msg.length()) {
                    // Traling newline => print it and done
                    out.println("");
                    start = pend;
                    break;
                }
            }
            else {
                if (efflw > end-pend) { // Room left on current line
                    efflw -= end-pend;
                    pend = end;
                    continue;
                }
                else { // Filled-up current line => print it
                    for (i=0; i<lind; i++) {
                        out.print(" ");
                    }
                    if (start == pend) { // Word larger than line width
                        // Print anyways
                        out.println(msg.substring(start,end));
                        pend = end;
                    }
                    else {
                        out.println(msg.substring(start,pend));
                    }
                }
            }
            // Initialize for next line
            lind = ind;
            efflw = lw-ind;
            start = nextWord(msg,pend);
            pend = start;
            if (start == IS_EOS) {
                break; // Did all the string
            }
        }
        if (pend != start) { // Part of a line left => print it
            for (i=0; i<lind; i++) {
                out.print(" ");
            }
            out.println(msg.substring(start,pend));
        }
    }
    /**
     * Returns the index of the last character of the next word, plus 1, or
     * IS_NEWLINE if a newline character is encountered before the next word,
     * or IS_EOS if the end of the string is ecnounterd before the next
     * word. The method first skips all whitespace characters at or after
     * "from", except newlines. If a newline is found IS_NEWLINE is
     * returned. Then it skips all non-whitespace characters and returns the
     * position of the last non-whitespace character, plus 1. The returned
     * index may be greater than the last valid index in the tsring, but it is
     * always suitable to be used in the String.substring() method.
     *
     * <P>Non-whitespace characters are defined as in the
     * Character.isWhitespace method (that method is used).
     *
     * @param str The string to parse
     *
     * @param from The index of the first position to search from
     *
     * @return The index of the last character in the next word, plus 1,
     * IS_NEWLINE, or IS_EOS if there are no more words.
     *
     *
     * */
    private int nextLineEnd(String str, int from) {
        final int len = str.length();
        char c = "\0";
        // First skip all whitespace, except new line
        while (from < len && (c = str.charAt(from)) != "\n" &&
               Character.isWhitespace(c)) {
            from++;
        }
        if (c == "\n") {
            return IS_NEWLINE;
        }
        if (from >= len) {
            return IS_EOS;
        }
        // Now skip word characters
        while (from < len && !Character.isWhitespace(str.charAt(from))) {
            from++;
        }
        return from;
    }
    /**
     * Returns the position of the first character in the next word, starting
     * from "from", if a newline is encountered first then the index of the
     * newline character plus 1 is returned. If the end of the string is
     * encountered then IS_EOS is returned. Words are defined as any
     * concatenation of 1 or more characters which are not
     * whitespace. Whitespace characters are those for which
     * Character.isWhitespace() returns true (that method is used).
     *
     * <P>Non-whitespace characters are defined as in the
     * Character.isWhitespace method (that method is used).
     *
     * @param str The string to parse
     *
     * @param from The index where to start parsing
     *
     * @return The index of the first character of the next word, or the index
     * of the newline plus 1, or IS_EOS.
     *
     *
     * */
    private int nextWord(String str, int from) {
        final int len = str.length();
        char c = "\0";
        // First skip all whitespace, but new lines
        while (from < len && (c = str.charAt(from)) != "\n" &&
               Character.isWhitespace(c)) {
            from++;
        }
        if (from >= len) {
            return IS_EOS;
        }
        else if (c == "\n") {
            return from+1;
        }
        else {
            return from;
        }
    }
}





Scans java source files in cvs tree and validates the license header

 
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.SyncFailedException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * A utility which scans all java source files in the cvs tree and validates the
 * license header prior to the package statement for headers that match those
 * declared in varia/src/etc/license-info.xml
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 81038 $
 */
public class ValidateLicenseHeaders {
  /** Used to strip out diffs due to copyright date ranges */
  static final String COPYRIGHT_REGEX = "copyright\\s(\\(c\\))*\\s*[\\d]+(\\s*,\\s*[\\d]+|\\s*-\\s*[\\d]+)*";
  static final String DEFAULT_HEADER = "/*\n" + " * JBoss, Home of Professional Open Source.\n"
      + " * Copyright 2008, Red Hat Middleware LLC, and individual contributors\n"
      + " * as indicated by the @author tags. See the copyright.txt file in the\n"
      + " * distribution for a full listing of individual contributors.\n" + " *\n"
      + " * This is free software; you can redistribute it and/or modify it\n"
      + " * under the terms of the GNU Lesser General Public License as\n"
      + " * published by the Free Software Foundation; either version 2.1 of\n"
      + " * the License, or (at your option) any later version.\n" + " *\n"
      + " * This software is distributed in the hope that it will be useful,\n"
      + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
      + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
      + " * Lesser General Public License for more details.\n" + " *\n"
      + " * You should have received a copy of the GNU Lesser General Public\n"
      + " * License along with this software; if not, write to the Free\n"
      + " * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA\n"
      + " * 02110-1301 USA, or see the FSF site: http://www.fsf.org.\n" + " */\n";
  static Logger log = Logger.getLogger("ValidateCopyrightHeaders");
  static boolean addDefaultHeader = false;
  static FileFilter dotJavaFilter = new DotJavaFilter();
  /**
   * The term-headers from the varia/src/etc/license-info.xml
   */
  static TreeMap licenseHeaders = new TreeMap();
  /**
   * Java source files with no license header
   */
  static ArrayList noheaders = new ArrayList();
  /**
   * Java source files with a header that does not match one from licenseHeaders
   */
  static ArrayList invalidheaders = new ArrayList();
  /** Total java source files seen */
  static int totalCount;
  /** Total out of date jboss headers seen */
  static int jbossCount;
  /**
   * ValidateLicenseHeaders jboss-src-root
   * 
   * @param args
   */
  public static void main(String[] args) throws Exception {
    if (args.length == 0 || args[0].startsWith("-h")) {
      log.info("Usage: ValidateLicenseHeaders [-addheader] jboss-src-root");
      System.exit(1);
    }
    int rootArg = 0;
    if (args.length == 2) {
      if (args[0].startsWith("-add"))
        addDefaultHeader = true;
      else {
        log.severe("Uknown argument: " + args[0]);
        log.info("Usage: ValidateLicenseHeaders [-addheader] jboss-src-root");
        System.exit(1);
      }
      rootArg = 1;
    }
    File jbossSrcRoot = new File(args[rootArg]);
    if (jbossSrcRoot.exists() == false) {
      log.info("Src root does not exist, check " + jbossSrcRoot.getAbsolutePath());
      System.exit(1);
    }
    URL u = Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/services/javax.xml.parsers.DocumentBuilderFactory");
    System.err.println(u);
    // Load the valid copyright statements for the licenses
    File licenseInfo = new File(jbossSrcRoot, "varia/src/etc/license-info.xml");
    if (licenseInfo.exists() == false) {
      log.severe("Failed to find the varia/src/etc/license-info.xml under the src root");
      System.exit(1);
    }
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = factory.newDocumentBuilder();
    Document doc = db.parse(licenseInfo);
    NodeList licenses = doc.getElementsByTagName("license");
    for (int i = 0; i < licenses.getLength(); i++) {
      Element license = (Element) licenses.item(i);
      String key = license.getAttribute("id");
      ArrayList headers = new ArrayList();
      licenseHeaders.put(key, headers);
      NodeList copyrights = license.getElementsByTagName("terms-header");
      for (int j = 0; j < copyrights.getLength(); j++) {
        Element copyright = (Element) copyrights.item(j);
        copyright.normalize();
        String id = copyright.getAttribute("id");
        // The id will be blank if there is no id attribute
        if (id.length() == 0)
          continue;
        String text = getElementContent(copyright);
        if (text == null)
          continue;
        // Replace all duplicate whitespace and "*" with a single space
        text = text.replaceAll("[\\s*]+", " ");
        if (text.length() == 1)
          continue;
        text = text.toLowerCase().trim();
        // Replace any copyright date0-date1,date2 with copyright ...
        text = text.replaceAll(COPYRIGHT_REGEX, "...");
        LicenseHeader lh = new LicenseHeader(id, text);
        headers.add(lh);
      }
    }
    log.fine(licenseHeaders.toString());
    File[] files = jbossSrcRoot.listFiles(dotJavaFilter);
    log.info("Root files count: " + files.length);
    processSourceFiles(files, 0);
    log.info("Processed " + totalCount);
    log.info("Updated jboss headers: " + jbossCount);
    // Files with no headers details
    log.info("Files with no headers: " + noheaders.size());
    FileWriter fw = new FileWriter("NoHeaders.txt");
    for (Iterator iter = noheaders.iterator(); iter.hasNext();) {
      File f = (File) iter.next();
      fw.write(f.getAbsolutePath());
      fw.write("\n");
    }
    fw.close();
    // Files with unknown headers details
    log.info("Files with invalid headers: " + invalidheaders.size());
    fw = new FileWriter("InvalidHeaders.txt");
    for (Iterator iter = invalidheaders.iterator(); iter.hasNext();) {
      File f = (File) iter.next();
      fw.write(f.getAbsolutePath());
      fw.write("\n");
    }
    fw.close();
    // License usage summary
    log.info("Creating HeadersSummary.txt");
    fw = new FileWriter("HeadersSummary.txt");
    for (Iterator iter = licenseHeaders.entrySet().iterator(); iter.hasNext();) {
      Map.Entry entry = (Map.Entry) iter.next();
      String key = (String) entry.getKey();
      fw.write("+++ License type=" + key);
      fw.write("\n");
      List list = (List) entry.getValue();
      Iterator jiter = list.iterator();
      while (jiter.hasNext()) {
        LicenseHeader lh = (LicenseHeader) jiter.next();
        fw.write("\t");
        fw.write(lh.id);
        fw.write(", count=");
        fw.write("" + lh.count);
        fw.write("\n");
      }
    }
    fw.close();
  }
  /**
   * Get all non-comment content from the element.
   * 
   * @param element
   * @return the concatenated text/cdata content
   */
  public static String getElementContent(Element element) {
    if (element == null)
      return null;
    NodeList children = element.getChildNodes();
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < children.getLength(); i++) {
      Node child = children.item(i);
      if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {
        result.append(child.getNodeValue());
      } else if (child.getNodeType() == Node.ruMENT_NODE) {
        // Ignore comment nodes
      } else {
        result.append(child.getFirstChild());
      }
    }
    return result.toString().trim();
  }
  /**
   * Validate the headers of all java source files
   * 
   * @param files
   * @param level
   * @throws IOException
   */
  static void processSourceFiles(File[] files, int level) throws IOException {
    for (int i = 0; i < files.length; i++) {
      File f = files[i];
      if (level == 0)
        log.info("processing " + f);
      if (f.isDirectory()) {
        File[] children = f.listFiles(dotJavaFilter);
        processSourceFiles(children, level + 1);
      } else {
        parseHeader(f);
      }
    }
  }
  /**
   * Read the first comment upto the package ...; statement
   * 
   * @param javaFile
   */
  static void parseHeader(File javaFile) throws IOException {
    totalCount++;
    RandomAccessFile raf = new RandomAccessFile(javaFile, "rw");
    String line = raf.readLine();
    StringBuffer tmp = new StringBuffer();
    long endOfHeader = 0;
    boolean packageOrImport = false;
    while (line != null) {
      long nextEOH = raf.getFilePointer();
      line = line.trim();
      // Ignore any single line comments
      if (line.startsWith("//")) {
        line = raf.readLine();
        continue;
      }
      // If this is a package/import/class/interface statement break
      if (line.startsWith("package") || line.startsWith("import") || line.indexOf("class") >= 0
          || line.indexOf("interface") >= 0) {
        packageOrImport = true;
        break;
      }
      // Update the current end of header marker
      endOfHeader = nextEOH;
      if (line.startsWith("/**"))
        tmp.append(line.substring(3));
      else if (line.startsWith("/*"))
        tmp.append(line.substring(2));
      else if (line.startsWith("*"))
        tmp.append(line.substring(1));
      else
        tmp.append(line);
      tmp.append(" ");
      line = raf.readLine();
    }
    raf.close();
    if (tmp.length() == 0 || packageOrImport == false) {
      addDefaultHeader(javaFile);
      return;
    }
    String text = tmp.toString();
    // Replace all duplicate whitespace with a single space
    text = text.replaceAll("[\\s*]+", " ");
    text = text.toLowerCase().trim();
    // Replace any copyright date0-date1,date2 with copyright ...
    text = text.replaceAll(COPYRIGHT_REGEX, "...");
    if (tmp.length() == 0) {
      addDefaultHeader(javaFile);
      return;
    }
    // Search for a matching header
    boolean matches = false;
    String matchID = null;
    Iterator iter = licenseHeaders.entrySet().iterator();
    escape: while (iter.hasNext()) {
      Map.Entry entry = (Map.Entry) iter.next();
      String key = (String) entry.getKey();
      List list = (List) entry.getValue();
      Iterator jiter = list.iterator();
      while (jiter.hasNext()) {
        LicenseHeader lh = (LicenseHeader) jiter.next();
        if (text.startsWith(lh.text)) {
          matches = true;
          matchID = lh.id;
          lh.count++;
          lh.usage.add(javaFile);
          if (log.isLoggable(Level.FINE))
            log.fine(javaFile + " matches copyright key=" + key + ", id=" + lh.id);
          break escape;
        }
      }
    }
    text = null;
    tmp.setLength(0);
    if (matches == false)
      invalidheaders.add(javaFile);
    else if (matchID.startsWith("jboss") && matchID.endsWith("#0") == false) {
      // This is a legacy jboss head that needs to be updated to the default
      replaceHeader(javaFile, endOfHeader);
      jbossCount++;
    }
  }
  /**
   * Replace a legacy jboss header with the current default header
   * 
   * @param javaFile -
   *          the java source file
   * @param endOfHeader -
   *          the offset to the end of the legacy header
   * @throws IOException -
   *           thrown on failure to replace the header
   */
  static void replaceHeader(File javaFile, long endOfHeader) throws IOException {
    if (log.isLoggable(Level.FINE))
      log.fine("Replacing legacy jboss header in: " + javaFile);
    RandomAccessFile raf = new RandomAccessFile(javaFile, "rw");
    File bakFile = new File(javaFile.getAbsolutePath() + ".bak");
    FileOutputStream fos = new FileOutputStream(bakFile);
    fos.write(DEFAULT_HEADER.getBytes());
    FileChannel fc = raf.getChannel();
    long count = raf.length() - endOfHeader;
    fc.transferTo(endOfHeader, count, fos.getChannel());
    fc.close();
    fos.close();
    raf.close();
    if (javaFile.delete() == false)
      log.severe("Failed to delete java file: " + javaFile);
    if (bakFile.renameTo(javaFile) == false)
      throw new SyncFailedException("Failed to replace: " + javaFile);
  }
  /**
   * Add the default jboss lgpl header
   */
  static void addDefaultHeader(File javaFile) throws IOException {
    if (addDefaultHeader) {
      FileInputStream fis = new FileInputStream(javaFile);
      FileChannel fc = fis.getChannel();
      int size = (int) fc.size();
      ByteBuffer contents = ByteBuffer.allocate(size);
      fc.read(contents);
      fis.close();
      ByteBuffer hdr = ByteBuffer.wrap(DEFAULT_HEADER.getBytes());
      FileOutputStream fos = new FileOutputStream(javaFile);
      fos.write(hdr.array());
      fos.write(contents.array());
      fos.close();
    }
    noheaders.add(javaFile);
  }
  /**
   * A class that encapsulates the license id and valid terms header
   */
  static class LicenseHeader {
    String id;
    String text;
    int count;
    ArrayList usage = new ArrayList();
    LicenseHeader(String id, String text) {
      this.id = id;
      this.text = text;
    }
  }
  /**
   * A filter which accepts files ending in .java (but not _Stub.java), or
   * directories other than gen-src and gen-parsers
   */
  static class DotJavaFilter implements FileFilter {
    public boolean accept(File pathname) {
      boolean accept = false;
      String name = pathname.getName();
      if (pathname.isDirectory()) {
        // Ignore the gen-src directories for generated output
        accept = name.equals("gen-src") == false && name.equals("gen-parsers") == false;
      } else {
        accept = name.endsWith("_Stub.java") == false && name.endsWith(".java");
      }
      return accept;
    }
  }
}





Swing Console

    
/*
 * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
 * 
 * http://izpack.org/
 * http://izpack.codehaus.org/
 * 
 * Copyright 2002 Jan Blok
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.Segment;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.Vector;
public final class Console
{
    public static final int INITIAL_WIDTH = 800;
    public static final int INITIAL_HEIGHT = 600;
    public static void main(String[] args)
    {
        Runtime rt = Runtime.getRuntime();
        Process p = null;
        try
        {
            /*
             * Start a new process in which to execute the commands in cmd, using the environment in
             * env and use pwd as the current working directory.
             */
            p = rt.exec(args);// , env, pwd);
            new Console(p);
            System.exit(p.exitValue());
        }
        catch (IOException e)
        {
            /*
             * Couldn"t even get the command to start. Most likely it couldn"t be found because of a
             * typo.
             */
            System.out.println("Error starting: " + args[0]);
            System.out.println(e);
        }
    }
    private StdOut so;
    private StdOut se;
    public String getOutputData()
    {
        if (so != null)
        {
            return so.getData();
        }
        else
        {
            return "";
        }
    }
    public String getErrorData()
    {
        if (se != null)
        {
            return se.getData();
        }
        else
        {
            return "";
        }
    }
    public Console(Process p)
    {
        JFrame frame = new JFrame();
        frame.setTitle("Console");
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation(screenSize.width / 2 - INITIAL_WIDTH / 2, screenSize.height / 2
                - INITIAL_HEIGHT / 2);
        ConsoleTextArea cta = new ConsoleTextArea();
        JScrollPane scroll = new JScrollPane(cta);
        scroll.setPreferredSize(new Dimension(INITIAL_WIDTH, INITIAL_HEIGHT));
        frame.getContentPane().add(scroll);
        frame.pack();
        // From here down your shell should be pretty much
        // as it is written here!
        /*
         * Start up StdOut, StdIn and StdErr threads that write the output generated by the process
         * p to the screen, and feed the keyboard input into p.
         */
        so = new StdOut(p, cta);
        se = new StdOut(p, cta);
        StdIn si = new StdIn(p, cta);
        so.start();
        se.start();
        si.start();
        // Wait for the process p to complete.
        try
        {
            frame.setVisible(true);
            p.waitFor();
        }
        catch (InterruptedException e)
        {
            /*
             * Something bad happened while the command was executing.
             */
            System.out.println("Error during execution");
            System.out.println(e);
        }
        /*
         * Now signal the StdOut, StdErr and StdIn threads that the process is done, and wait for
         * them to complete.
         */
        try
        {
            so.done();
            se.done();
            si.done();
            so.join();
            se.join();
            si.join();
        }
        catch (InterruptedException e)
        {
            // Something bad happend to one of the Std threads.
            System.out.println("Error in StdOut, StdErr or StdIn.");
            System.out.println(e);
        }
        frame.setVisible(false);
    }
}
class StdIn extends Thread
{
    private BufferedReader kb;
    private boolean processRunning;
    private PrintWriter op;
    public StdIn(Process p, ConsoleTextArea cta)
    {
        setDaemon(true);
        InputStreamReader ir = new InputStreamReader(cta.getIn());
        kb = new BufferedReader(ir);
        BufferedOutputStream os = new BufferedOutputStream(p.getOutputStream());
        op = new PrintWriter((new OutputStreamWriter(os)), true);
        processRunning = true;
    }
    public void run()
    {
        try
        {
            while (kb.ready() || processRunning)
            {
                if (kb.ready())
                {
                    op.println(kb.readLine());
                }
            }
        }
        catch (IOException e)
        {
            System.err.println("Problem reading standard input.");
            System.err.println(e);
        }
    }
    public void done()
    {
        processRunning = false;
    }
}
class StdOut extends Thread
{
    private InputStreamReader output;
    private boolean processRunning;
    private ConsoleTextArea cta;
    private StringBuffer data;
    public StdOut(Process p, ConsoleTextArea cta)
    {
        setDaemon(true);
        output = new InputStreamReader(p.getInputStream());
        this.cta = cta;
        processRunning = true;
        data = new StringBuffer();
    }
    public void run()
    {
        try
        {
            /*
             * Loop as long as there is output from the process to be displayed or as long as the
             * process is still running even if there is presently no output.
             */
            while (output.ready() || processRunning)
            {
                // If there is output get it and display it.
                if (output.ready())
                {
                    char[] array = new char[255];
                    int num = output.read(array);
                    if (num != -1)
                    {
                        String s = new String(array, 0, num);
                        data.append(s);
                        SwingUtilities.invokeAndWait(new ConsoleWrite(cta, s));
                    }
                }
            }
        }
        catch (Exception e)
        {
            System.err.println("Problem writing to standard output.");
            System.err.println(e);
        }
    }
    public void done()
    {
        processRunning = false;
    }
    public String getData()
    {
        return data.toString();
    }
}
class ConsoleWrite implements Runnable
{
    private ConsoleTextArea textArea;
    private String str;
    public ConsoleWrite(ConsoleTextArea textArea, String str)
    {
        this.textArea = textArea;
        this.str = str;
    }
    public void run()
    {
        textArea.write(str);
    }
}
class ConsoleWriter extends java.io.OutputStream
{
    private ConsoleTextArea textArea;
    private StringBuffer buffer;
    public ConsoleWriter(ConsoleTextArea textArea)
    {
        this.textArea = textArea;
        buffer = new StringBuffer();
    }
    public synchronized void write(int ch)
    {
        buffer.append((char) ch);
        if (ch == "\n")
        {
            flushBuffer();
        }
    }
    public synchronized void write(char[] data, int off, int len)
    {
        for (int i = off; i < len; i++)
        {
            buffer.append(data[i]);
            if (data[i] == "\n")
            {
                flushBuffer();
            }
        }
    }
    public synchronized void flush()
    {
        if (buffer.length() > 0)
        {
            flushBuffer();
        }
    }
    public void close()
    {
        flush();
    }
    private void flushBuffer()
    {
        String str = buffer.toString();
        buffer.setLength(0);
        SwingUtilities.invokeLater(new ConsoleWrite(textArea, str));
    }
}
class ConsoleTextArea extends JTextArea implements KeyListener, DocumentListener
{
    /**
     *
     */
    private static final long serialVersionUID = 3258410625414475827L;
    private ConsoleWriter console1;
    private PrintStream out;
    private PrintStream err;
    private PrintWriter inPipe;
    private PipedInputStream in;
    private Vector<String> history;
    private int historyIndex = -1;
    private int outputMark = 0;
    public void select(int start, int end)
    {
        requestFocus();
        super.select(start, end);
    }
    public ConsoleTextArea()
    {
        super();
        history = new java.util.Vector<String>();
        console1 = new ConsoleWriter(this);
        ConsoleWriter console2 = new ConsoleWriter(this);
        out = new PrintStream(console1);
        err = new PrintStream(console2);
        PipedOutputStream outPipe = new PipedOutputStream();
        inPipe = new PrintWriter(outPipe);
        in = new PipedInputStream();
        try
        {
            outPipe.connect(in);
        }
        catch (IOException exc)
        {
            exc.printStackTrace();
        }
        getDocument().addDocumentListener(this);
        addKeyListener(this);
        setLineWrap(true);
        setFont(new Font("Monospaced", 0, 12));
    }
    void returnPressed()
    {
        Document doc = getDocument();
        int len = doc.getLength();
        Segment segment = new Segment();
        try
        {
            synchronized (doc)
            {
                doc.getText(outputMark, len - outputMark, segment);
            }
        }
        catch (javax.swing.text.BadLocationException ignored)
        {
            ignored.printStackTrace();
        }
        if (segment.count > 0)
        {
            history.addElement(segment.toString());
        }
        historyIndex = history.size();
        inPipe.write(segment.array, segment.offset, segment.count);
        append("\n");
        synchronized (doc)
        {
            outputMark = doc.getLength();
        }
        inPipe.write("\n");
        inPipe.flush();
        console1.flush();
    }
    public void eval(String str)
    {
        inPipe.write(str);
        inPipe.write("\n");
        inPipe.flush();
        console1.flush();
    }
    public void keyPressed(KeyEvent e)
    {
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT)
        {
            if (outputMark == getCaretPosition())
            {
                e.consume();
            }
        }
        else if (code == KeyEvent.VK_HOME)
        {
            int caretPos = getCaretPosition();
            if (caretPos == outputMark)
            {
                e.consume();
            }
            else if (caretPos > outputMark)
            {
                if (!e.isControlDown())
                {
                    if (e.isShiftDown())
                    {
                        moveCaretPosition(outputMark);
                    }
                    else
                    {
                        setCaretPosition(outputMark);
                    }
                    e.consume();
                }
            }
        }
        else if (code == KeyEvent.VK_ENTER)
        {
            returnPressed();
            e.consume();
        }
        else if (code == KeyEvent.VK_UP)
        {
            historyIndex--;
            if (historyIndex >= 0)
            {
                if (historyIndex >= history.size())
                {
                    historyIndex = history.size() - 1;
                }
                if (historyIndex >= 0)
                {
                    String str = history.elementAt(historyIndex);
                    int len = getDocument().getLength();
                    replaceRange(str, outputMark, len);
                    int caretPos = outputMark + str.length();
                    select(caretPos, caretPos);
                }
                else
                {
                    historyIndex++;
                }
            }
            else
            {
                historyIndex++;
            }
            e.consume();
        }
        else if (code == KeyEvent.VK_DOWN)
        {
            int caretPos = outputMark;
            if (history.size() > 0)
            {
                historyIndex++;
                if (historyIndex < 0)
                {
                    historyIndex = 0;
                }
                int len = getDocument().getLength();
                if (historyIndex < history.size())
                {
                    String str = history.elementAt(historyIndex);
                    replaceRange(str, outputMark, len);
                    caretPos = outputMark + str.length();
                }
                else
                {
                    historyIndex = history.size();
                    replaceRange("", outputMark, len);
                }
            }
            select(caretPos, caretPos);
            e.consume();
        }
    }
    public void keyTyped(KeyEvent e)
    {
        int keyChar = e.getKeyChar();
        if (keyChar == 0x8 /* KeyEvent.VK_BACK_SPACE */)
        {
            if (outputMark == getCaretPosition())
            {
                e.consume();
            }
        }
        else if (getCaretPosition() < outputMark)
        {
            setCaretPosition(outputMark);
        }
    }
    public void keyReleased(KeyEvent e)
    {
    }
    public synchronized void write(String str)
    {
        insert(str, outputMark);
        int len = str.length();
        outputMark += len;
        select(outputMark, outputMark);
    }
    public synchronized void insertUpdate(DocumentEvent e)
    {
        int len = e.getLength();
        int off = e.getOffset();
        if (outputMark > off)
        {
            outputMark += len;
        }
    }
    public synchronized void removeUpdate(DocumentEvent e)
    {
        int len = e.getLength();
        int off = e.getOffset();
        if (outputMark > off)
        {
            if (outputMark >= off + len)
            {
                outputMark -= len;
            }
            else
            {
                outputMark = off;
            }
        }
    }
    public void postUpdateUI()
    {
        // this attempts to cleanup the damage done by updateComponentTreeUI
        requestFocus();
        setCaret(getCaret());
        synchronized (this)
        {
            select(outputMark, outputMark);
        }
    }
    public void changedUpdate(DocumentEvent e)
    {
    }
    public InputStream getIn()
    {
        return in;
    }
    public PrintStream getOut()
    {
        return out;
    }
    public PrintStream getErr()
    {
        return err;
    }
}





Trace InputStream

   
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)TraceInputStream.java  1.8 07/05/04
 */

import java.io.*;
/**
 * This class is a FilterInputStream that writes the bytes
 * being read from the given input stream into the given output
 * stream. This class is typically used to provide a trace of
 * the data that is being retrieved from an input stream.
 *
 * @author John Mani
 */
public class TraceInputStream extends FilterInputStream {
    private boolean trace = false;
    private boolean quote = false;
    private OutputStream traceOut;
    /**
     * Creates an input stream filter built on top of the specified
     * input stream.
     *   
     * @param   in   the underlying input stream.
     * @param   out  the trace stream
     */
    public TraceInputStream(InputStream in, OutputStream traceOut) {
  super(in);
  this.traceOut = traceOut;
    }
    /**
     * Set trace mode.
     * @param trace the trace mode
     */
    public void setTrace(boolean trace) {
  this.trace = trace;
    }
    /**
     * Set quote mode.
     * @param quote the quote mode
     */
    public void setQuote(boolean quote) {
  this.quote = quote;
    }
    /**
     * Reads the next byte of data from this input stream. Returns
     * <code>-1</code> if no data is available. Writes out the read
     * byte into the trace stream, if trace mode is <code>true</code>
     */
    public int read() throws IOException {
  int b = in.read();
  if (trace && b != -1) {
      if (quote)
    writeByte(b);
      else
    traceOut.write(b);
  }
  return b;
    }
    /**
     * Reads up to <code>len</code> bytes of data from this input stream
     * into an array of bytes. Returns <code>-1</code> if no more data
     * is available. Writes out the read bytes into the trace stream, if 
     * trace mode is <code>true</code>
     */
    public int read(byte b[], int off, int len) throws IOException {
  int count = in.read(b, off, len);
  if (trace && count != -1) {
      if (quote) {
    for (int i = 0; i < count; i++)
        writeByte(b[off + i]);
      } else
    traceOut.write(b, off, count);
  }
  return count;
    }
    /**
     * Write a byte in a way that every byte value is printable ASCII.
     */
    private final void writeByte(int b) throws IOException {
  b &= 0xff;
  if (b > 0x7f) {
      traceOut.write("M");
      traceOut.write("-");
      b &= 0x7f;
  }
  if (b == "\r") {
      traceOut.write("\\");
      traceOut.write("r");
  } else if (b == "\n") {
      traceOut.write("\\");
      traceOut.write("n");
      traceOut.write("\n");
  } else if (b == "\t") {
      traceOut.write("\\");
      traceOut.write("t");
  } else if (b < " ") {
      traceOut.write("^");
      traceOut.write("@" + b);
  } else {
      traceOut.write(b);
  }
    }
}





Trace OutputStream

   
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)TraceOutputStream.java 1.6 07/05/04
 */
import java.io.*;
/**
 * This class is a subclass of DataOutputStream that copies the
 * data being written into the DataOutputStream into another output
 * stream. This class is used here to provide a debug trace of the
 * stuff thats being written out into the DataOutputStream.
 *
 * @author John Mani
 */
public class TraceOutputStream extends FilterOutputStream {
    private boolean trace = false;
    private boolean quote = false;
    private OutputStream traceOut;
    /**
     * Creates an output stream filter built on top of the specified
     * underlying output stream.
     *
     * @param   out   the underlying output stream.
     * @param traceOut  the trace stream.
     */
    public TraceOutputStream(OutputStream out, OutputStream traceOut) {
  super(out);
  this.traceOut = traceOut;
    }
    /**
     * Set the trace mode.
     */
    public void setTrace(boolean trace) {
  this.trace = trace;
    }
    /**
     * Set quote mode.
     * @param quote the quote mode
     */
    public void setQuote(boolean quote) {
  this.quote = quote;
    }
    /**
     * Writes the specified <code>byte</code> to this output stream.
     * Writes out the byte into the trace stream if the trace mode
     * is <code>true</code>
     */
    public void write(int b) throws IOException {
  if (trace) {
      if (quote)
    writeByte(b);
      else
    traceOut.write(b);
  }
  out.write(b);
    }
      
    /**
     * Writes <code>b.length</code> bytes to this output stream.
     * Writes out the bytes into the trace stream if the trace
     * mode is <code>true</code>
     */
    public void write(byte b[], int off, int len) throws IOException {
  if (trace) {
      if (quote) {
    for (int i = 0; i < len; i++)
        writeByte(b[off + i]);
      } else
    traceOut.write(b, off, len);
  }
  out.write(b, off, len);
    }
    /**
     * Write a byte in a way that every byte value is printable ASCII.
     */
    private final void writeByte(int b) throws IOException {
  b &= 0xff;
  if (b > 0x7f) {
      traceOut.write("M");
      traceOut.write("-");
      b &= 0x7f;
  }
  if (b == "\r") {
      traceOut.write("\\");
      traceOut.write("r");
  } else if (b == "\n") {
      traceOut.write("\\");
      traceOut.write("n");
      traceOut.write("\n");
  } else if (b == "\t") {
      traceOut.write("\\");
      traceOut.write("t");
  } else if (b < " ") {
      traceOut.write("^");
      traceOut.write("@" + b);
  } else {
      traceOut.write(b);
  }
    }
}