You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ba...@apache.org on 2002/02/22 06:57:15 UTC

cvs commit: jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception Nestable.java NestableDelegate.java NestableException.java NestableRuntimeException.java

bayard      02/02/21 21:57:15

  Added:       lang/src/java/org/apache/commons/lang Classes.java
                        Numbers.java Objects.java Strings.java
               lang/src/java/org/apache/commons/lang/exception
                        Nestable.java NestableDelegate.java
                        NestableException.java
                        NestableRuntimeException.java
  Log:
  Initial commit of 'lang' classes from Commons.Utils.
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Classes.java
  
  Index: Classes.java
  ===================================================================
  package org.apache.commons.lang;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /**
   * A set of static utilities for use with Classes.
   *
   * @author  bayard@generationjava.com
   * @version $Id: Classes.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
   */
  final public class Classes {
  
      /**
       * Create an object from the classname. Must have an empty constructor.
       *
       * @param classname String name of the class
       *
       * @return Object instance of the class or null
       */
      static public Object createObject(String classname) {
          Class tmpClass = null;
  
          tmpClass = getClass(classname);
  
          return createObject(tmpClass);
      }
  
      /**
       * Create an object from a class. 
       *
       * @param clss Class object to instantiate
       *
       * @return Object instance of the class or null
       */
      static public Object createObject(Class clss) {
  
          try {
              return clss.newInstance();
          } catch (IllegalAccessException  iae) {
              System.err.println("Cant instantiate " + clss.getName() + " because " +
                     iae.getMessage());
          } catch (InstantiationException  ie) {
              System.err.println("Cant instantiate " + clss.getName() + " because " +
                     ie.getMessage());
          }
  
          return null;
      }
  
      /**
       * Is this Class in the CLASSPATH
       *
       * @param classname String of the class
       *
       * @return boolean exists or not.
       */
      static public boolean classExists(String classname) {
          Class tmpClass = null;
  
          /* try and load class */
          try {
              tmpClass = Class.forName(classname);
          } catch (ClassNotFoundException cnfe) {
              return false;
          } catch (IllegalArgumentException iae) {
              return false;
          }
       
          return true;   
      }
  
      /**
       * Get the Class object for a classname.
       *
       * @param classname String of the class
       *
       * @return Class instance for the class.
       */
      static public Class getClass(String classname) {
          Class tmpClass = null;
  
          /* try an load class */
          try {
              tmpClass = Class.forName(classname);
          } catch (ClassNotFoundException cnfe) {
              System.out.println("Can't resolve classname " + classname);
          } catch (IllegalArgumentException iae) {
              System.err.println("Cant resolve " + tmpClass.getName() + " because " + iae.getMessage());
          }
       
          return tmpClass;   
      }
  
      /**
       * Is this Class object an instance of the class with this name.
       *
       * @param clss Class instance
       * @param inst String name of potential supertype
       *
       * @return boolean was it an instanceof
       */
      static public boolean classInstanceOf(Class clss, String inst) {
          if(classImplements(clss,inst)) {
              return true;
          } else
          if(classExtends(clss,inst)) {
              return true;
          } else {
              return false;
          }
      }
  
      /**
       * Does this Class implement an interface with this name.
       *
       * @param clss Class instance
       * @param exts String name of potential interface
       *
       * @return boolean was it an implementor
       */
      static public boolean classImplements(Class clss, String exts) {
  
        Class sprcls = clss;
        Class excls  = getClass(exts);
  
        while(sprcls != null) {
          Class[] interfaces = sprcls.getInterfaces();
  
          for(int i=0;i<interfaces.length;i++) {
              if(interfaces[i].equals(excls)) {
                  return true;
              }
          }
  
          sprcls = sprcls.getSuperclass();
        }
  
        return false;
      }
  
      /**
       * Does this Class extend a superclass with this name.
       *
       * @param clss Class instance
       * @param exts String name of potential superclass
       *
       * @return boolean was it a superclass
       */
      static public boolean classExtends(Class clss, String exts) {
          if(clss == null) {
              return false;
          }
          if(clss.getName().equals(exts)) {
              return true;
          }
          Class sprcls = clss.getSuperclass();
          Class excls = getClass(exts);
  
  //        while(! sprcls.equals(sprcls.getSuperclass()) ) {
          while( sprcls != null ) {
              if(sprcls.equals(excls)) {
                  return true;
              }
              sprcls = sprcls.getSuperclass();
          }
          return false;
      }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Numbers.java
  
  Index: Numbers.java
  ===================================================================
  package org.apache.commons.lang;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Commons" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.math.BigInteger;
  import java.math.BigDecimal;
  
  /**
   * Provides extra functionality for java Number classes.
   *
   * @author bayard@generationjava.com
   * @version $Id: Numbers.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
   */
  final public class Numbers {
  
      static public int stringToInt(String str) {
          return stringToInt(str,0);
      }
      static public int stringToInt(String str, int def) {
          try {
              return Integer.parseInt(str);
          } catch(NumberFormatException nfe) {
              return def;
          }
      }
  
      // must handle Long, Float, Integer, Float, Short,
      //                  BigDecimal, BigInteger and Byte
      // useful methods:
      // Byte.decode(String)
      // Byte.valueOf(String,int radix)
      // Byte.valueOf(String)
      // Double.valueOf(String)
      // Float.valueOf(String)
      // new Float(String)
      // Integer.valueOf(String,int radix)
      // Integer.valueOf(String)
      // Integer.decode(String)
      // Integer.getInteger(String)
      // Integer.getInteger(String,int val)
      // Integer.getInteger(String,Integer val)
      // new Integer(String)
      // new Double(String)
      // new Byte(String)
      // new Long(String)
      // Long.getLong(String)
      // Long.getLong(String,int)
      // Long.getLong(String,Integer)
      // Long.valueOf(String,int)
      // Long.valueOf(String)
      // new Short(String)
      // Short.decode(String)
      // Short.valueOf(String,int)
      // Short.valueOf(String)
      // new BigDecimal(String)
      // new BigInteger(String)
      // new BigInteger(String,int radix)
      // Possible inputs:
      // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
      // plus minus everything. Prolly more. A lot are not separable.
  
      /**
       * Turns a string value into a java.lang.Number.
       * Strategy is to look for a decimal point. If that is seen then
       * try first float and then try double.
       * If this fails, then try int and then long.
       * Assuming 50f fails and isn't 50, then try hexadecimal.
       *
       * @param val String containing a number
       *
       * @return Number created from the string
       */
      static public Number createNumber(String val) 
              throws NumberFormatException 
      {
          if (val == null) {
              return null;
          }
  
          int idx = val.indexOf('.');                
          if ( (idx != -1) && (idx != val.length()-1) )  {
              try {
                  return createFloat(val);
              } catch (NumberFormatException nfe) {
              }
              try {
                  return createDouble(val);
              } catch (NumberFormatException nfe) {
              }
  
              // look for all digits or '.' with f or F on end.
              if( val.endsWith("f") || val.endsWith("F") ) {
                  String mant = val.substring(0,idx);
                  String dec = val.substring(idx+1,val.length()-1);
                  if(containsDigits(mant) && containsDigits(dec) ) {
                      try {
                          return createFloat(val.substring(0,val.length()-1));
                      } catch (NumberFormatException nfe) {
                      }
                  }
              }
  
              // look for all digits or '.' with d or D on end.
              if( val.endsWith("d") || val.endsWith("D") ) {
                  String mant = val.substring(0,idx);
                  String dec = val.substring(idx+1,val.length()-1);
                  if(containsDigits(mant) && containsDigits(dec) ) {
                      try {
                          return createDouble(val.substring(0,val.length()-1));
                      } catch (NumberFormatException nfe) {
                      }
                  }
              }
  
              try {
                  return createBigDecimal(val);
              } catch (NumberFormatException nfe) {
              }
  
              throw new NumberFormatException("Unable to convert: "+val);
          }
  
          try {
              return createInteger(val);
          } catch (NumberFormatException nfe) {
          }
          try {
              return createLong(val);
          } catch (NumberFormatException nfe) {
          }
  
  
          // look for all digits with l or L on the end.
          if( val.endsWith("l") || val.endsWith("L") ) {
              if(containsDigits(val.substring(0,val.length()-1))) {
                  try {
                      return createLong(val.substring(0,val.length()-1));
                  } catch (NumberFormatException nfe) {
                  }
              }
          }
  
  
          try {
              return createBigInteger(val);
          } catch (NumberFormatException nfe) {
          }
  
          // try Hex.
          try {
              return Integer.valueOf(val,16);
          } catch (NumberFormatException nfe) {
          }
  
          throw new NumberFormatException("Unable to convert: "+val);
      }
  
      /**
       * Return true if the string contains only digit characters.
       *
       * @param val String to check is only digits
       *
       * @return boolean contains only unicode numeric
       */
      static public boolean containsDigits(String val) {
          if(val == null) {
              return false; // ???
          }
          for(int i=0;i<val.length();i++) {
              if(!Character.isDigit(val.charAt(i))) {
                  return false;
              }
          }
          return true;
      }
  
      static public Float createFloat(String val) {
          return Float.valueOf(val);
      }
  
      static public Double createDouble(String val) {
          return Double.valueOf(val);
      }
  
      // handles 0xAABD and 0777 (hex and octal) as well.
      static public Integer createInteger(String val) {
          // return Integer.valueOf(val);
          return Integer.decode(val);
      }
  
      static public Long createLong(String val) {
          return Long.valueOf(val);
      }
  
      static public BigInteger createBigInteger(String val) {
          BigInteger bi = new BigInteger(val);
          return bi;
      }
  
      static public BigDecimal createBigDecimal(String val) {
          BigDecimal bd = new BigDecimal(val);
          return bd;
      }
  
      /**
       * Get the minimum of three values.
       */
      static public int minimum(int a, int b, int c) {
          if(b < a) {
              a = b;
          }
          if(c < a) {
              a = c;
          }
          return a;
      }
  
      /**
       * Is a String a valid Java number.
       * Doesn't allow scientific notation.
       */
      static public boolean isNumber(String str) {
          char[] chrs = str.toCharArray();
          int sz = chrs.length;
          boolean decimal = false;
          for(int i=0; i<sz; i++) {
              // possibly faster as a continuous switch
              if( (chrs[i] >= '0') && (chrs[i] <= '9') ) {
                  continue;
              }
              if(i==0) {
                  if(chrs[i] == '-') {
                      continue;
                  }
              }
              if(chrs[i] == '.') {
                  if(!decimal) {
                      decimal = true;
                      continue;
                  }
              }
              return false;
          }
          return true;
      }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Objects.java
  
  Index: Objects.java
  ===================================================================
  package org.apache.commons.lang;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.BufferedInputStream;
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.ObjectInputStream;
  
  /**
   * Common <code>Object</code> manipulation routines.
   *
   * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
   * @author <a href="mailto:janekdb@yahoo.co.uk">Janek Bogucki</a>
   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
   * @version $Id: Objects.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
   */
  public class Objects
  {
      /**
       * Returns a default value if the object passed is null.
       *
       * @param o The object to test.
       * @param dflt The default value to return.
       * @return The object o if it is not null, dflt otherwise.
       */
      public static Object isNull(Object o, Object dflt)
      {
          return (o != null ? o : dflt);
      }
  
      /**
       * Deserializes a single object from an array of bytes.
       *
       * @param objectData The serialized object.
       * @return The deserialized object, or <code>null</code> on failure.
       */
      public static Object deserialize(byte[] objectData)
      {
          Object object = null;
          if (objectData != null)
          {
              ObjectInputStream in = null;
              try
              {
                  InputStream bin = new ByteArrayInputStream(objectData);
                  in = new ObjectInputStream(bin);
  
                  // If objectData has not been initialized, an
                  // exception will occur.
                  object = in.readObject();
              }
              catch (Exception returnNull)
              {
              }
              finally
              {
                  try
                  {
                      if (in != null)
                      {
                          in.close();
                      }
                  }
                  catch (IOException ignored)
                  {
                  }
              }
          }
          return object;
      }
  
      /**
       * Compares two objects for equality, where either one or both
       * objects may be <code>null</code>.
       *
       * @param o1 The first object.
       * @param o2 The second object.
       * @return True if the values of both objects are the same.
       */
      public static boolean equals(Object o1, Object o2)
      {
          if (o1 == null)
          {
              return (o2 == null);
          }
          else if (o2 == null)
          {
              // o1 is not null
              return false;
          }
          else
          {
              return o1.equals(o2);
          }
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Strings.java
  
  Index: Strings.java
  ===================================================================
  package org.apache.commons.lang;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.InputStreamReader;
  import java.io.OutputStreamWriter;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.io.IOException;
  import java.util.NoSuchElementException;
  import java.util.StringTokenizer;
  
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Random;
  
  // CharSet
  import java.util.List;
  import java.util.LinkedList;
  
  
  /**
   * <p>Common <code>String</code> manipulation routines.</p>
   *
   * <p>Originally from <a
   * href="http://jakarta.apache.org/turbine/">Turbine</a> and the
   * GenerationJavaCore library.</p>
   *
   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
   * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
   * @author <a href="mailto:bayard@generationjava.com">Bayard</a>
   * @author <a href="mailto:ed@apache.org">Ed Korthof</a>
   * @version $Id: Strings.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
   */
  public class Strings
  {
      /**
       * The size of the buffer to use when working with I/O (4 kB).
       */
      //public static int CHAR_BUFFER_SIZE = 4 * FileUtils.ONE_KB;
      public static int CHAR_BUFFER_SIZE = 4 * 1024;
  
      /**
       * Trims text safely, dealing with <code>null</code> references by
       * converting them to <code>""</code> (the empty string).
       *
       * @param s The text to trim.
       * @return The trimmed text (never <code>null</code>).
       */
      public static final String clean(String s)
      {
          return (s == null ? "" : s.trim());
      }
  
      /**
       * Trims text safely, dealing with <code>null</code> references by
       * returning <code>null</code> (rather than throwing a
       * NullPointerException).
       *
       * @param s The text to trim.
       * @return The trimmed text (or <code>null</code>).
       */
      public static final String trim(String s)
      {
          return (s == null ? null : s.trim());
      }
  
      /**
       * Validates that the supplied string is neither <code>null</code>
       * nor the empty string.
       *
       * @param text The text to check.
       * @return Whether valid.
       */
      public static final boolean isValid(String text)
      {
          return (text != null && text.length() > 0);
      }
  
      /**
       * Determine whether a (trimmed) string is empty
       *
       * @param foo The text to check.
       * @return Whether empty.
       */
      public static final boolean isEmpty(String foo)
      {
          return (foo == null || foo.trim().length() == 0);
      }
  
      /**
       * Returns the output of printStackTrace as a String.
       *
       * @param e The source to extract a stack trace from.
       * @return The extracted stack trace.
       */
      public static final String stackTrace(Throwable e)
      {
          String trace = null;
          try
          {
              // And show the Error Screen.
              ByteArrayOutputStream buf = new ByteArrayOutputStream();
              e.printStackTrace( new PrintWriter(buf, true) );
              trace = buf.toString();
          }
          catch (Exception ignored)
          {
          }
          return trace;
      }
  
      /**
       * Safely compares two <code>String</code> objects, returning
       * whether their values are the same.  Two <code>null</code>
       * references are considered equal.
       *
       * @param s1 The first string.
       * @param s2 The second string.
       * @return Whether the values of both strings are the same.
       */
      public static boolean equals(String s1, String s2)
      {
          return (s1 == null ? s2 == null : s1.equals(s2));
      }
  
      /**
       * Takes a String of the form <code>substring[substring]substring</code>
       * and returns the three parsed substrings.
       *
       * @return A three element {@link java.lang.String} array populated by
       * any parsed object key components.
       */
      public static String[] parseObjectKey(String s)
      {
          String[] objectKey = new String[3];
          StringTokenizer st = new StringTokenizer(s, "[]");
          int count = st.countTokens();
          if (count > 1)
          {
              objectKey[0] = st.nextToken();
              objectKey[1] = st.nextToken();
              if (count == 3)
              {
                  objectKey[2] = st.nextToken();
              }
          }
          return objectKey;
      }
  
      /**
       * Removes underscores from text.
       *
       * @param text The text to remove any underscores from.
       * @return The underscore-less text.
       * @deprecated Use replace(String, String, String) instead.
       */
      public static String removeUnderScores(String text)
      {
          return replace(text, "_", "", -1);
      }
  
      /**
       * Makes the first letter capital and leaves the rest as is.
       *
       * @param text The text to modify.
       * @return The modified text.
       */
      public static String firstLetterCaps(String text)
      {
          return (text == null ? null :
                  text.substring(0, 1).toUpperCase() + text.substring(1));
      }
  
      /**
       * @see #split(String text, String separator, int max)
       */
      public static String[] split(String text)
      {
          return split(text, " ", -1);
      }
  
      /**
       * @see #split(String text, String separator, int max)
       */
      public static String[] split(String text, String separator)
      {
          return split(text, separator, -1);
      }
  
      /**
       * Splits the provided text into a list, based on a given
       * separator.
       *
       * @param text Textual list to parse.
       * @param separator The separator character.
       * @param max The maximum number of elements to include in the
       * list.  A value of <code>-1</code> implies no limit.
       * @return The list of values.
       */
      public static String[] split(String text, String separator, int max)
      {
          StringTokenizer tok = new StringTokenizer(text, separator);
          int listSize = tok.countTokens();
          if (max != -1 && listSize > max)
          {
              listSize = max;
          }
  
          String[] list = new String[listSize];
          int i = 0;
          while (tok.hasMoreTokens())
          {
              if (max != -1 && i == listSize - 1)
              {
                  // In the situation where we hit the max yet have
                  // tokens left over in our input, the last list
                  // element gets all remaining text.
                  StringBuffer buf = new StringBuffer
                      ((int) 1.2 * text.length() * (listSize - i) / listSize);
                  while (tok.hasMoreTokens())
                  {
                      buf.append(tok.nextToken());
                      if (tok.hasMoreTokens())
                      {
                          buf.append(separator);
                      }
                  }
                  list[i] = buf.toString();
                  break;
              }
              else
              {
                  list[i] = tok.nextToken();
              }
              i++;
          }
          return list;
      }
  
      /**
       * Joins the elements of the provided array into a single string
       * containing the provided list of elements.  No delimiter is
       * added before or after the list.
       *
       * @param list      The list of values to join together.
       * @param separator The separator character.
       * @return          The CSV text.
       */
      public static String join(Object[] list, String separator)
      {
          int listSize = list.length;
          int bufSize = (listSize == 0 ? 0 :(list[0].toString().length() +
                                             separator.length()) * listSize);
          StringBuffer buf = new StringBuffer(bufSize);
              
          for (int i = 0; i < listSize; i++)
          {
              if (i > 0)
              {
                  buf.append(separator);
              }
              buf.append(list[i]);
          }
          return buf.toString();
      }
  
      /**
       * Merges the list of <code>Object</code> intances supplied by an
       * <code>Iterator</code> into a single piece text.  No delimiter
       * is added before or after the list.
       *
       * @param iterator The list provider.
       * @param separator String delimiter to separate list elements
       * with.
       * @return Text delimited list as a <code>String</code>.
       */
      public static String join(Iterator iterator, String separator)
      {
          StringBuffer buf = new StringBuffer();
          while (iterator.hasNext())
          {
              buf.append(iterator.next());
              if (iterator.hasNext())
              {
                  buf.append(separator);
              }
          }
          return buf.toString();
      }
  
      /**
       * Takes a block of text which might have long lines in it and wraps
       * the long lines based on the supplied wrapColumn parameter. It was
       * initially implemented for use by VelocityEmail. If there are tabs
       * in inString, you are going to get results that are a bit strange,
       * since tabs are a single character but are displayed as 4 or 8
       * spaces. Remove the tabs.
       *
       * @param inString   Text which is in need of word-wrapping.
       * @param newline    The characters that define a newline.
       * @param wrapColumn The column to wrap the words at.
       * @return           The text with all the long lines word-wrapped.
       */
  
      public static String wrapText (String inString, String newline,
                                     int wrapColumn)
      {
          StringTokenizer lineTokenizer = new StringTokenizer (
                  inString, newline, true);
          StringBuffer stringBuffer = new StringBuffer();
  
          while (lineTokenizer.hasMoreTokens ())
          {
              try
              {
                  String nextLine = lineTokenizer.nextToken();
  
                  if (nextLine.length() > wrapColumn)
                  {
                      // This line is long enough to be wrapped.
                      nextLine = wrapLine (nextLine, newline, wrapColumn);
                  }
  
                  stringBuffer.append (nextLine);
              }
              catch (NoSuchElementException nsee)
              {
                  // thrown by nextToken(), but I don't know why it would
                  break;
              }
          }
  
          return (stringBuffer.toString());
      }
  
      /**
       * Wraps a single line of text. Called by wrapText(). I can't
       * think of any good reason for exposing this to the public,
       * since wrapText should always be used AFAIK.
       *
       * @param line       A line which is in need of word-wrapping.
       * @param newline    The characters that define a newline.
       * @param wrapColumn The column to wrap the words at.
       * @return           A line with newlines inserted.
       */
  
      protected static String wrapLine (String line, String newline,
                                        int wrapColumn)
      {
          StringBuffer wrappedLine = new StringBuffer();
  
          while (line.length() > wrapColumn)
          {
              int spaceToWrapAt = line.lastIndexOf (' ', wrapColumn);
  
              if (spaceToWrapAt >= 0)
              {
                  wrappedLine.append (line.substring (0, spaceToWrapAt));
                  wrappedLine.append (newline);
                  line = line.substring (spaceToWrapAt + 1);
              }
  
              // This must be a really long word or URL. Pass it
              // through unchanged even though it's longer than the
              // wrapColumn would allow. This behavior could be
              // dependent on a parameter for those situations when
              // someone wants long words broken at line length.
              else
              {
                  spaceToWrapAt = line.indexOf (' ', wrapColumn);
  
                  if (spaceToWrapAt >= 0)
                  {
                      wrappedLine.append (line.substring (0, spaceToWrapAt));
                      wrappedLine.append (newline);
                      line = line.substring (spaceToWrapAt + 1);
                  }
                  else
                  {
                      wrappedLine.append (line);
                      line = "";
                  }
              }
          }
  
          // Whatever is left in line is short enough to just pass through,
          // just like a small small kidney stone
          wrappedLine.append (line);
  
          return (wrappedLine.toString());
      }
  
      /**
       * Uncapitalise a string. That is, convert the first character into 
       * lower-case.
       *
       * @param str String to uncapitalise
       *
       * @return String uncapitalised
       */
      static public String uncapitalise(String str) {
          return str.substring(0,1).toLowerCase() + str.substring(1);
      }
  
      /**
       * Capitalise a string. That is, convert the first character into 
       * title-case.
       *
       * @param str String to capitalise
       *
       * @return String capitalised
       */
      static public String capitalise(String str) {
          return "" + Character.toTitleCase(str.charAt(0)) + str.substring(1);
      }
  
      /**
       * Replace a string with another string inside a larger string, once.
       *
       * @see #replace(String text, String repl, String with, int max)
       */
      public static String replaceOnce(String text, String repl, String with)
      {
          return replace(text, repl, with, 1);
      }
  
      /**
       * @see #replace(String text, String repl, String with, int max)
       */
      public static String replace(String text, String repl, String with)
      {
          return replace(text, repl, with, -1);
      }
  
      /**
       * @see #replace(String text, String repl, String with, int max)
       */
      public static String replace(String text, String repl, String with,
                                   String max)
      {
          return replace(text, repl, with, Numbers.stringToInt(max, -1));
      }
  
      /**
       * Replace a string with another string inside a larger string,
       * for the first <code>max</code> values of the search string.  A
       * <code>null</code> reference is passed to this method is a
       * no-op.
       *
       * @param text Text to search and replace in.
       * @param repl String to search for
       * @param with String to replace with
       * @param max Maximum number of values to replace, or
       * <code>-1</code> if no maximum.
       * @return The text with any replacements processed.
       */
      public static String replace(String text, String repl, String with,
                                   int max)
      {
          if (text == null)
          {
              return null;
          }
  
          StringBuffer buf = new StringBuffer(text.length());
          int start = 0, end = 0;
          while ( (end = text.indexOf(repl, start)) != -1 )
          {
              //System.err.println("end=" + end);
              buf.append(text.substring(start, end)).append(with);
              start = end + repl.length();
              //System.err.println("new start=" + start);
  
              if (--max == 0)
              {
                  break;
              }
          }
          buf.append(text.substring(start));
          return buf.toString();
      }
  
      static public String overlayString(String text, String overlay, String start, String end) {
          return overlayString(text,overlay,Numbers.stringToInt(start), Numbers.stringToInt(end));
      }
      /**
       * Overlay a part of a string with another string.
       *
       * @param text String to do overlaying in
       * @param overlay String to overlay
       * @param start int to start overlaying at
       * @param end   int to stop overlaying before
       *
       * @return String with overlayed text
       */
      static public String overlayString(String text, String overlay, int start, int end) {
          String pre = text.substring(0, start);
          String post = text.substring(end);
          return pre+overlay+post;
      }
  
      static public String repeat(String str, String n) {
          return repeat(str, Numbers.stringToInt(n,1));
      }
  
      /**
       * Repeat a string n times to form a new string.
       *
       * @param str String to repeat
       * @param n   int    number of times to repeat
       *
       * @return String with repeated string
       */
      static public String repeat(String str, int n) {
          StringBuffer buffer = new StringBuffer(n*str.length());
          for(int i=0; i<n; i++) {
              buffer.append(str);
          }
          return buffer.toString();
      }
  
  // these are not really of use in the Java world. Only if you're a C afficionado
  //    static public String sprintf(String format, Object[] list);
  //    static public Object[] sscanf(String str, String format);
  //    static public String pack(String[] strs, String format);
  //    static public String[] unpack(String str, String format);
  
  
      /**
       * Center a string in a larger string of size n.
       * Uses spaces as the value to buffer the string with..
       *
       * @param str String to center
       * @param n   int    size of new String
       *
       * @return String containing centered String
       */
      static public String center(String str, int n) {
          return center(str, n, " ");
      }
  
      static public String center(String str, String n, String delim) {
          return center(str,Numbers.stringToInt(n), delim);
      }
  
      /**
       * Center a string in a larger string of size n.
       * Uses a supplied String as the value to buffer the string with..
       *
       * @param str String to center
       * @param n   int    size of new String
       * @param delim String to buffer the new String with
       *
       * @return String containing centered String
       */
      static public String center(String str, int n, String delim) {
          int sz = str.length();
          int p = n-sz;
          if(p < 1) {
              return str;
          }
          str = leftPad(str,sz+p/2, delim);
          str = rightPad(str, n, delim);
          return str;
      }
  
      /** 
       * Remove the last newline, and everything after it from a String.
       *
       * @param str String to chomp the newline from
       *
       * @return String without chomped newline
       */
      static public String chomp(String str) {
          return chomp(str, "\n");
      }
      
      /** 
       * Remove the last value of a supplied String, and everything after it 
       * from a String.
       *
       * @param str String to chomp from
       * @param sep String to chomp
       *
       * @return String without chomped ending
       */
      static public String chomp(String str, String sep) {
          int idx = str.lastIndexOf(sep);
          if(idx != -1) {
              return str.substring(0,idx);
          } else {
              return str;
          }
      }
      
      /**
       * Remove a newline if and only if it is at the end 
       * of the supplied string.
       */
      static public String chompLast(String str) {
          return chompLast(str, "\n");
      }
      static public String chompLast(String str, String sep) {
          if(str.length() == 0) {
              return str;
          }
          String sub = str.substring(str.length() - sep.length());
          if(sep.equals(sub)) {
              return str.substring(0,str.length()-sep.length());
          } else {
              return str;
          }
      }
  
      /** 
       * Remove everything and return the last value of a supplied String, and 
       * everything after it from a String.
       *
       * @param str String to chomp from
       * @param sep String to chomp
       *
       * @return String chomped
       */
      static public String getChomp(String str, String sep) {
          int idx = str.lastIndexOf(sep);
          if(idx == str.length()-sep.length()) {
              return sep;
          } else
          if(idx != -1) {
              return str.substring(idx);
          } else {
              return "";
          }
      }
  
      /** 
       * Remove the first value of a supplied String, and everything before it 
       * from a String.
       *
       * @param str String to chomp from
       * @param sep String to chomp
       *
       * @return String without chomped beginning
       */
      static public String prechomp(String str, String sep) {
          int idx = str.indexOf(sep);
          if(idx != -1) {
              return str.substring(idx+sep.length());
          } else {
              return str;
          }
      }
  
      /** 
       * Remove and return everything before the first value of a 
       * supplied String from another String.
       *
       * @param str String to chomp from
       * @param sep String to chomp
       *
       * @return String prechomped
       */
      static public String getPrechomp(String str, String sep) {
          int idx = str.indexOf(sep);
          if(idx != -1) {
              return str.substring(0,idx+sep.length());
          } else {
              return "";
          }
      }
  
      /**
       * Remove the last character from a String. If the String 
       * ends in \r\n, then remove both of them.
       *
       * @param str String to chop last character from
       *
       * @return String without last character
       */
      static public String chop(String str) {
          if("".equals(str)) {
              return "";
          }
          if(str.length() == 1) {
              return "";
          }
          int lastIdx = str.length()-1;
          String ret = str.substring(0,lastIdx);
          char last = str.charAt(lastIdx);
          if(last == '\n') {
              if(ret.charAt(lastIdx-1) == '\r') {
                  return ret.substring(0,lastIdx-1);
              }
          }
          return ret;
      }
  
      /**
       * Remove \n from end of a String if it's there.
       * If a \r precedes it, then remove that too.
       *
       * @param str String to chop a newline from
       *
       * @param String without newline on end
       */
      static public String chopNewline(String str) {
          int lastIdx = str.length()-1;
          char last = str.charAt(lastIdx);
          if(last == '\n') {
              if(str.charAt(lastIdx-1) == '\r') {
                  lastIdx --;
              }
          } else {
              lastIdx++;
          }
          return str.substring(0,lastIdx);
      }
  
      /**
       * Creates a CharSet object which allows a certain amount of 
       * set logic to be performed upon the following syntax:
       *
       * "aeio" which implies 'a','e',..
       * "^e" implies not e. However it only negates, it's not 
       * a set in itself due to the size of that set in unicode.
       * "ej-m" implies e,j->m. e,j,k,l,m.
       */
      static public CharSet evaluateSet(String[] set) {
          return new CharSet(set); 
      }
  
      static public int count(String str, String set) {
          String[] strs = new String[1];
          strs[0] = set;
          return count(str, strs);
      }
      /**
       * Takes an argument in set-syntax, see evaluateSet,
       * and returns the number of characters present in the specified string.
       * An example would be:   count("hello", {"c-f","o"}) returns 2.
       *
       * @param str String target to count characters in
       * @param str String[] set of characters to count
       */
      static public int count(String str, String[] set) {
          CharSet chars = evaluateSet(set);
          int count = 0;
          char[] chrs = str.toCharArray();
          int sz = chrs.length;
          for(int i=0; i<sz; i++) {
              if(chars.contains(chrs[i])) {
                  count++;
              }
          }
          return count;
      }
  
      static public String delete(String str, String set) {
          String[] strs = new String[1];
          strs[0] = set;
          return delete(str, strs);
      }
      /**
       * Takes an argument in set-syntax, see evaluateSet,
       * and deletes any of characters present in the specified string.
       * An example would be:   delete("hello", {"c-f","o"}) returns "hll"
       *
       * @param str String target to delete characters from
       * @param str String[] set of characters to delete
       */
      static public String delete(String str, String[] set) {
          CharSet chars = evaluateSet(set);
          StringBuffer buffer = new StringBuffer(str.length());
          char[] chrs = str.toCharArray();
          int sz = chrs.length;
          for(int i=0; i<sz; i++) {
              if(!chars.contains(chrs[i])) {
                  buffer.append(chrs[i]);
              }
          }
          return buffer.toString();
      }
  
      static public String squeeze(String str, String set) {
          String[] strs = new String[1];
          strs[0] = set;
          return squeeze(str, strs);
      }
      /**
       * Squeezes any repititions of a character that is mentioned in the 
       * supplied set. An example is:
       *    squeeze("hello", {"el"})  => "helo"
       * See evaluateSet for set-syntax.
       */
      static public String squeeze(String str, String[] set) {
          CharSet chars = evaluateSet(set);
          StringBuffer buffer = new StringBuffer(str.length());
          char[] chrs = str.toCharArray();
          int sz = chrs.length;
          char lastChar = ' ';
          char ch = ' ';
          for(int i=0; i<sz; i++) {
              ch = chrs[i];
              if(chars.contains(ch)) {
                  if( (ch == lastChar) && (i != 0) ) {
                      continue;
                  }
              }
              buffer.append(ch);
              lastChar = ch;
          }
          return buffer.toString();
      }
  
      /**
       * Translate characters in a String.
       * An example is:  translate("hello", "ho", "jy") => jelly
       * If the length of characters to search for is greater than the 
       * length of characters to replace, then the last character is 
       * used.
       *
       * @param target String to replace characters  in
       * @param repl String to find that will be replaced
       * @param with String to put into the target String
       */
      static public String translate(String target, String repl, String with) {
          StringBuffer buffer = new StringBuffer(target.length());
          char[] chrs = target.toCharArray();
          char[] withChrs = with.toCharArray();
          int sz = chrs.length;
          int withMax = with.length() - 1;
          for(int i=0; i<sz; i++) {
              int idx = repl.indexOf(chrs[i]);
              if(idx != -1) {
                  if(idx > withMax) {
                      idx = withMax;
                  }
                  buffer.append(withChrs[idx]);
              } else {
                  buffer.append(chrs[i]);
              }
          }
          return buffer.toString();
      }
      
      // spec 3.10.6
      /**
       * Escapes any values it finds into their String form.
       * So a tab becomes the characters '\\' and 't'.
       *
       * @param str String to escape values in
       *
       * @return String with escaped values
       */
      // improved with code from  cybertiger@cyberiantiger.org
      // unicode from him, and defaul for < 32's.
      static public String escape(String str) {
          int sz = str.length();
          StringBuffer buffer = new StringBuffer(2*sz);
          for(int i=0; i<sz; i++) {
              char ch = str.charAt(i);
  
              // handle unicode
              if(ch > 0xfff) {
                  buffer.append("\\u"+Integer.toHexString(ch));
              } else 
              if(ch > 0xff) {
                  buffer.append("\\u0"+Integer.toHexString(ch));
              } else 
              if(ch > 0x7f) {
                  buffer.append("\\u00"+Integer.toHexString(ch));
              } else 
              if(ch < 32) {
                  switch(ch) {
                      case '\b' : 
                          buffer.append('\\');
                          buffer.append('b');
                          break;
                      case '\n' : 
                          buffer.append('\\');
                          buffer.append('n');
                          break;
                      case '\t' : 
                          buffer.append('\\');
                          buffer.append('t');
                          break;
                      case '\f' : 
                          buffer.append('\\');
                          buffer.append('f');
                          break;
                      case '\r' : 
                          buffer.append('\\');
                          buffer.append('r');
                          break;
                      default :
                          if( ch > 0xf ) {
                              buffer.append("\\u00"+Integer.toHexString(ch));
                          } else {
                              buffer.append("\\u000"+Integer.toHexString(ch));
                          }
                          break;
                  }
              } else {
                  switch(ch) {
                      case '\'' : 
                          buffer.append('\\');
                          buffer.append('\'');
                          break;
                      case '"' : 
                          buffer.append('\\');
                          buffer.append('"');
                          break;
                      case '\\' : 
                          buffer.append('\\');
                          buffer.append('\\');
                          break;
                      default :
                          buffer.append(ch);
                          break;
                  }
              }
          }
          return buffer.toString();
      }
  
      /**
       * Right pad a String with spaces. Pad to a size of n.
       */
      static public String rightPad(String str, int n) {
          return rightPad(str, n, " ");
      }
      static public String rightPad(String str, String n, String delim) {
          return rightPad(str, Numbers.stringToInt(n), delim);
      }
      /**
       * Right pad a String with a specified string. Pad to a size of n.
       *
       * @param str   String to pad out
       * @param n     int    size to pad to
       * @param delim String to pad with
       */
      static public String rightPad(String str, int n, String delim) {
          n = (n - str.length())/delim.length();
          if(n > 0) {
              str += repeat(delim,n);
          }
          return str;
      }
  
      /**
       * Left pad a String with spaces. Pad to a size of n.
       */
      static public String leftPad(String str, int n) {
          return leftPad(str, n, " ");
      }
      static public String leftPad(String str, String n, String delim) {
          return leftPad(str, Numbers.stringToInt(n), delim);
      }
      /**
       * Left pad a String with a specified string. Pad to a size of n.
       *
       * @param str   String to pad out
       * @param n     int    size to pad to
       * @param delim String to pad with
       */
      static public String leftPad(String str, int n, String delim) {
          n = (n - str.length())/delim.length();
          if(n > 0) {
              str = repeat(delim,n) + str;
          }
          return str;
      }
  
      // faster algorithm available. unsure if usable in Java
      /**
       * Reverse a String.
       */
      static public String reverse(String str) {
          /*
          int sz = str.length();
          StringBuffer buffer = new StringBuffer(sz);
          for(int i=sz; i>0; i--) {
              buffer.append(str.charAt(i-1));
          }
          return buffer.toString();
          */
          return new StringBuffer(str).reverse().toString();
      }
  
      /**
       * Remove whitespace from the front and back of a String.
       */
      static public String strip(String str) {
          return strip(str, null);
      }
      /**
       * Remove a specified String from the front and back of a 
       * String. If Whitespace is wanted to be removed, used the 
       * strip(String) method.
       */
      static public String strip(String str, String delim) {
          str = stripStart(str, delim);
          return stripEnd(str, delim);
      }
  
      /**
       * Swaps the case of String. Properly looks after 
       * making sure the start of words are Titlecase and not 
       * Uppercase.
       */
      static public String swapCase(String str) {
          int sz = str.length();
          StringBuffer buffer = new StringBuffer(sz);
  
          boolean whitespace = false;
          char ch = 0;
          char tmp = 0;
  
          for(int i=0; i<sz; i++) {
              ch = str.charAt(i);
              if(Character.isUpperCase(ch)) {
                  tmp = Character.toLowerCase(ch);
              } else
              if(Character.isTitleCase(ch)) {
                  tmp = Character.toLowerCase(ch);
              } else
              if(Character.isLowerCase(ch)) {
                  if(whitespace) {
                      tmp = Character.toTitleCase(ch);
                  } else {
                      tmp = Character.toUpperCase(ch);
                  }
              } 
              buffer.append(tmp);
              whitespace = Character.isWhitespace(ch);
          }
          return buffer.toString();
      }
  
  
      // From .NET
      /**
       * Find the earlier index of any of a set of potential substrings.
       */
      static public int indexOfAny(String str, String[] strs) {
          int sz = strs.length;
  
          // String's can't have a MAX_VALUEth index.
          int ret = Integer.MAX_VALUE;  
  
          int tmp = 0;
          for(int i=0; i<sz; i++) {
              tmp = str.indexOf(strs[i]);
              if(tmp == -1) {
                  continue;
              }
  
              if(tmp < ret) {
                  ret = tmp;
              }
          }
  
          return (ret == Integer.MAX_VALUE)?-1:ret;
      }
  
      /**
       * Find the latest index of any of a set of potential substrings.
       */
      static public int lastIndexOfAny(String str, String[] strs) {
          int sz = strs.length;
          int ret = -1;
          int tmp = 0;
          for(int i=0; i<sz; i++) {
              tmp = str.lastIndexOf(strs[i]);
              if(tmp > ret) {
                  ret = tmp;
              }
          }
          return ret;
      }
  
      /**
       * Strip any of a supplied substring from the end of a String..
       */
      static public String stripEnd(String str, String ch) {
          int end = str.length();
  
          if(ch == null) {
              while( Character.isWhitespace( str.charAt(end-1) ) ) {
                  end--;
              }
          } else {
              char chr = ch.charAt(0);
              while( str.charAt(end-1) == chr ) {
                  end--;
              }
          }
          return str.substring(0, end);
      }
  
      /**
       * Strip any of a supplied substring from the start of a String..
       */
      static public String stripStart(String str, String ch) {
          int start = 0;
  
          if(ch == null) {
              while( Character.isWhitespace( str.charAt(start) ) ) {
                  start++;
              }
          } else {
              char chr = ch.charAt(0);
              while( str.charAt(start) == chr ) {
                  start++;
              }
          }
          return str.substring(start);
      }
  
      /**
       * Find the Levenshtein distance between two strings.
       * This is the number of changes needed to change one string into 
       * another. Where each change is a single character modification.
       *
       * This implemmentation of the levenshtein distance algorithm 
       * is from http://www.merriampark.com/ld.htm
       */
      static public int getLevenshteinDistance(String s, String t) {
          int d[][]; // matrix
          int n; // length of s
          int m; // length of t
          int i; // iterates through s
          int j; // iterates through t
          char s_i; // ith character of s
          char t_j; // jth character of t
          int cost; // cost
  
          // Step 1
          n = s.length ();
          m = t.length ();
          if (n == 0) {
              return m;
          }
          if (m == 0) {
              return n;
          }
          d = new int[n+1][m+1];
  
          // Step 2
          for (i = 0; i <= n; i++) {
              d[i][0] = i;
          }
  
          for (j = 0; j <= m; j++) {
              d[0][j] = j;
          }
  
          // Step 3
          for (i = 1; i <= n; i++) {
              s_i = s.charAt (i - 1);
  
              // Step 4
              for (j = 1; j <= m; j++) {
                  t_j = t.charAt (j - 1);
  
                  // Step 5
                  if (s_i == t_j) {
                      cost = 0;
                  } else {
                      cost = 1;
                  }
  
                  // Step 6
                  d[i][j] = Numbers.minimum(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1] + cost);
              }
          }
  
          // Step 7
          return d[n][m];
      }
  
      /**
       * Quote a string so that it may be used in a regular expression 
       * without any parts of the string being considered as a 
       * part of the regular expression's control characters.
       */
      static public String quoteRegularExpression(String str) {
          // replace ? + * / . ^ $ as long as they're not in character 
          // class. so must be done by hand
          char[] chrs = str.toCharArray();
          int sz = chrs.length;
          StringBuffer buffer = new StringBuffer(2*sz);
          for(int i=0; i<sz; i++) {
              switch(chrs[i]) {
                case '[' :
                case ']' :
                case '?' :
                case '+' :
                case '*' :
                case '/' :
                case '.' :
                case '^' :
                case '$' :
                  buffer.append("\\");
                default : 
                  buffer.append(chrs[i]);
              }
          }
          return buffer.toString();
      }
  
      /**
       * Capitalise all the words in a string. Uses Character.isWhitespace 
       * as a separator between words.
       */
      static public String capitaliseAllWords(String str) {
          int sz = str.length();
          StringBuffer buffer = new StringBuffer(sz);
          boolean space = true;
          for(int i=0; i<sz; i++) {
              char ch = str.charAt(i);
              if(Character.isWhitespace(ch)) {
                  buffer.append(ch);
                  space = true;
              } else
              if(space) {
                  buffer.append(Character.toTitleCase(ch));
                  space = false;
              } else {
                  buffer.append(ch);
              }
          }
          return buffer.toString();
      }
  
      /**
       * Create a word-wrapped version of a String. Wrap at 80 characters and 
       * use newlines as the delimiter. If a word is over 80 characters long 
       * use a - sign to split it.
       */
      static public String wordWrap(String str) {
          return wordWrap(str, 80, "\n", "-");
      }
      /**
       * Create a word-wrapped version of a String. Wrap at a specified width and 
       * use newlines as the delimiter. If a word is over the width in lenght 
       * use a - sign to split it.
       */
      static public String wordWrap(String str, int width) {
          return wordWrap(str, width, "\n", "-");
      }
      static public String wordWrap(String str, String width, String delim, String split) {
          return wordWrap(str, Numbers.stringToInt(width), delim, split);
      }
      /**
       * Word-wrap a string.
       *
       * @param str   String to word-wrap
       * @param width int to wrap at
       * @param delim String to use to separate lines
       * @param split String to use to split a word greater than width long
       *
       * @return String that has been word wrapped
       */
      static public String wordWrap(String str, int width, String delim, String split) {
          int sz = str.length();
  
          /// shift width up one. mainly as it makes the logic easier
          width++;
  
          // our best guess as to an initial size
          StringBuffer buffer = new StringBuffer(sz/width*delim.length()+sz);
  
          // every line will include a delim on the end
          width = width - delim.length();
  
          int idx = -1;
          String substr = null;
  
          // beware: i is rolled-back inside the loop
          for(int i=0; i<sz; i+=width) {
  
              // on the last line
              if(i > sz - width) {
                  buffer.append(str.substring(i));
  //                System.err.print("LAST-LINE: "+str.substring(i));
                  break;
              }
  
  //            System.err.println("loop[i] is: "+i);
              // the current line
              substr = str.substring(i, i+width);
  
              // is the delim already on the line
              idx = substr.indexOf(delim);
              if(idx != -1) {
                  buffer.append(substr.substring(0,idx));
  //                System.err.println("Substr: '"+substr.substring(0,idx)+"'");
                  buffer.append(delim);
                  i -= width-idx-delim.length();
                  
  //                System.err.println("loop[i] is now: "+i);
  //                System.err.println("found-whitespace: '"+substr.charAt(idx+1)+"'.");
                  // Erase a space after a delim. Is this too obscure?
                  if(substr.charAt(idx+1) != '\n') {
                      if(Character.isWhitespace(substr.charAt(idx+1))) {
                          i++;
                      }
                  }
  //                System.err.println("i -= "+width+"-"+idx);
                  continue;
              }
  
              idx = -1;
  
              // figure out where the last space is
              char[] chrs = substr.toCharArray();
              for(int j=width; j>0; j--) {
                  if(Character.isWhitespace(chrs[j-1])) {
                      idx = j;
  //                    System.err.println("Found whitespace: "+idx);
                      break;
                  }
              }
  
              // idx is the last whitespace on the line.
  //            System.err.println("idx is "+idx);
              if(idx == -1) {
                  for(int j=width; j>0; j--) {
                      if(chrs[j-1] == '-') {
                          idx = j;
  //                        System.err.println("Found Dash: "+idx);
                          break;
                      }
                  }
                  if(idx == -1) {
                      buffer.append(substr);
                      buffer.append(delim);
  //                    System.err.print(substr);
  //                    System.err.print(delim);
                  } else {
                      if(idx != width) {
                          idx++;
                      }
                      buffer.append(substr.substring(0,idx));
                      buffer.append(delim);
  //                    System.err.print(substr.substring(0,idx));
  //                    System.err.print(delim);
                      i -= width-idx;
                  }
              } else {
                  /*
                  if(force) {
                      if(idx == width-1) {
                          buffer.append(substr);
                          buffer.append(delim);
                      } else {
                          // stick a split in.
                          int splitsz = split.length();
                          buffer.append(substr.substring(0,width-splitsz));
                          buffer.append(split);
                          buffer.append(delim);
                          i -= splitsz;
                      }
                  } else {
                  */
                      // insert spaces
                      buffer.append(substr.substring(0,idx));
                      buffer.append(repeat(" ",width-idx));
  //                    System.err.print(substr.substring(0,idx));
  //                    System.err.print(repeat(" ",width-idx));
                      buffer.append(delim);
  //                    System.err.print(delim);
  //                    System.err.println("i -= "+width+"-"+idx);
                      i -= width-idx;
  //                }
              }
          }
  //        System.err.println("\n*************");
          return buffer.toString();
      }
  
  
      /**
       * Get the String that is nested in between two instances of the 
       * same String.
       *
       * @param str   String containing nested-string
       * @param tag  String before and after nested-string
       *
       * @return String that was nested
       */
      static public String getNestedString(String str, String tag) {
          return getNestedString(str, tag, tag);
      }
      /**
       * Get the string that is nested in between two strings.
       *
       * @param str   String containing nested-string
       * @param open  String before nested-string
       * @param close String after nested-string
       *
       * @return String that was nested
       */
      static public String getNestedString(String str, String open, String close) {
          int start = str.indexOf(open);
          if(start != -1) {
              int end = str.indexOf(close, start+open.length());
              if(end != -1) {
                  return str.substring(start+open.length(), end);
              }
          }
          return "";
      }
  
  
      /**
       * How mmany times is the substring in the larger string.
       */
      static public int countMatches(String str, String sub) {
          int count = 0;
          int idx = 0;
          while( (idx = str.indexOf(sub, idx)) != -1) {
              count++;
              idx += sub.length();
          }
          return count;
      }
  
      /**
       * Is a String a word. Contains only unicode letters.
       */
      static public boolean isWord(String str) {
          int sz = str.length();
          for(int i=0; i<sz; i++) {
              if(!Character.isLetter(str.charAt(i))) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Does a String contain only unicode letters or digits.
       */
      static public boolean isAlphanumeric(String str) {
          int sz = str.length();
          for(int i=0; i<sz; i++) {
              if(!Character.isLetterOrDigit(str.charAt(i))) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Does a String contain only unicode digits.
       */
      static public boolean isNumeric(String str) {
          int sz = str.length();
          for(int i=0; i<sz; i++) {
              if(!Character.isDigit(str.charAt(i))) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Is a String a line, containing only letters, digits or 
       * whitespace, and ending with an optional newline.
       * NB: Punctuation not allowed.
       */
      static public boolean isLine(String str) {
          char ch = 0;
          char[] chrs = str.toCharArray();
          int sz = chrs.length-1;
          for(int i=0; i<sz-2; i++) {
              if(!Character.isLetterOrDigit(chrs[i])) {
                  if(!Character.isWhitespace(chrs[i])) {
                      return false;
                  }
              }
          }
          if(!Character.isLetterOrDigit(chrs[sz-1])) {
              if(!Character.isWhitespace(chrs[sz-1])) {
                  if(chrs[sz-1] != '\r') {
                      return false;
                  } else 
                  if(chrs[sz] != '\n') {
                      return false;
                  }
              }
          }
          if(!Character.isLetterOrDigit(chrs[sz])) {
              if(!Character.isWhitespace(chrs[sz])) {
                  if(chrs[sz] != '\n') {
                      return false;
                  }
              }
          }
          return true;
      }
  
      /*
      // needs to handle punctuation
      static public boolean isText(String str) {
          int sz = str.length();
          char ch = 0;
          for(int i=0; i<sz; i++) {
              ch = str.charAt(i);
              if(!Character.isLetterOrDigit(ch)) {
                  if(!Character.isWhitespace(ch)) {
                      if( (ch != '\n') && (ch != '\r') ) {
                          return false;
                      }
                  }
              }
          }
          return true;
      }
      */
  
      /**
       * Return either the passed in String, or if it is null, 
       * then an empty String.
       */
      static public String defaultString(String str) {
          return defaultString(str,"");
      }
  
      /**
       * Return either the passed in String, or if it is null, 
       * then a passed in default String.
       */
      static public String defaultString(String str, String def) {
          return (str == null)?def:str;
      }
  
      static public String upperCase(String str) {
          return str.toUpperCase();
      }
  
      static public String lowerCase(String str) {
          return str.toLowerCase();
      }
  
      static public String substring(String str, String start) {
          return substring(str, Numbers.stringToInt(start));
      }
      static public String substring(String str, int start) {
          if(str == null) {
              return null;
          }
  
          // handle negatives
          if(start < 0) {
              start = str.length() + start;    // remember start is negative
          }
  
          if(start < 0) {
              start = 0;
          }
  
          return str.substring(start);
      }
      static public String substring(String str, String start, String end) {
          return substring(str, Numbers.stringToInt(start), Numbers.stringToInt(end));
      }
      static public String substring(String str, int start, int end) {
          if(str == null) {
              return null;
          }
  
          // handle negatives
          if(end < 0) {
              end = str.length() + end;    // remember end is negative
          }
          if(start < 0) {
              start = str.length() + start;    // remember start is negative
          }
  
          // check length next
          if(end > str.length()) {
              // check this works.
              end = str.length();
          }
  
          // what if start is greater than end??
  
          if(start < 0) {
              start = 0;
          }
  
          // a good default?
          if(end < 0) {
              end = 0;
          }
  
          return str.substring(start, end);
      }
  
  
      static public String random(int count) {
          return random(count, false, false);
      }
  
      static public String randomAscii(int count) {
          return random(count, 32, 127, false, false);
      }
      static public String randomAlphabetic(int count) {
          return random(count, true, false);
      }
      static public String randomAlphanumeric(int count) {
          return random(count, true, true);
      }
      static public String randomNumeric(int count) {
          return random(count, false, true);
      }
  
      static public String random(int count, boolean letters, boolean numbers) {
          return random(count, 0, 0, letters, numbers);
      }
      static public String random(int count, int start, int end, boolean letters, boolean numbers) {
          return random(count, start, end, letters, numbers, null);
      }
      /**
       * Create a random string based on a variety of options.
       *
       * @param count int length of random string to create
       * @param start int position in set of chars to start at
       * @param end int position in set of chars to end before
       * @param letters boolean only allow letters?
       * @param numbers boolean only allow numbers?
       * @param set char[] set of chars to choose randoms from.
       *        If null, then it will use the set of all chars.
       *
       */
      static public String random(int count, int start, int end, boolean letters, boolean numbers, char[] set) {
          if( (start == 0) && (end == 0) ) {
              end = (int)'z';
              start = (int)' ';
              if(!letters && !numbers) {
                  start = 0;
                  end = Integer.MAX_VALUE;
              }
          }
          Random rnd = new Random();
          StringBuffer buffer = new StringBuffer();
          int gap = end - start;
  
          while(count-- != 0) {
              char ch;
              if(set == null) {
                  ch = (char)(rnd.nextInt(gap) + start);
              } else {
                  ch = set[rnd.nextInt(gap) + start];
              }
              if( (letters && numbers && Character.isLetterOrDigit(ch)) ||
                  (letters && Character.isLetter(ch)) ||
                  (numbers && Character.isDigit(ch)) ||
                  (!letters && !numbers)
                ) 
              {
                  buffer.append( ch );
              } else {
                  count++;
              }
          }
          return buffer.toString();
      }
  
      static public String random(int count, String set) {
          return random(count, set.toCharArray());
      }
  
      static public String random(int count, char[] set) {
          return random(count,0,set.length-1,false,false,set);
      }
  
      static public String reverseDottedName(String text) {
          return reverseDelimitedString(text, ".");
      }
  
      static public String reverseDelimitedString(String text, String delimiter) {
          // could implement manually, but simple way is to reuse other, 
          // probably slower, methods.
          String[] strs = split(text, delimiter);
  //        CollectionsUtils.reverseArray(strs);
  // call private method instead for the moment.
          reverseArray(strs);
          return join(strs, delimiter);
      }
  
  /// TAKEN FROM CollectionsUtils. Need to find a solution.
      static private void reverseArray(Object[] array) {
          int i = 0;
          int j = array.length - 1;
          Object tmp;
  
          while(j>i) {
              tmp = array[j];
              array[j] = array[i];
              array[i] = tmp;
              j--;
              i++;
          }
      }
  
  
      /**
       * Interpolate variables into a String.
       */
      static public String interpolate(String text, Map map) {
          Iterator keys = map.keySet().iterator();
          while(keys.hasNext()) {
              String key = keys.next().toString();
              String value = map.get(key).toString();
              text = replace(text, "${"+key+"}", value);
              if(key.indexOf(" ") == -1) {
                  text = replace(text, "$"+key, value);
              }
          }
          return text;
      }
  
      /**
       * Convert a string from unicode to bytes in a native encoding.
       * The string must be in unicode (as Java always expects this);
       * {@link #convertNativeToUnicode(String, String)} will convert
       * strings in native encodings into unicode.  This method is
       * generally used to create a <code>String</code> for use as
       * output, and is useful when dealing with I18N.
       *
       * @param source String the unicode string to convert
       * @param charset String the name of the charset into which to
       * convert.
       * @return The string given represented in the native encoding
       * specified.
       * @see #convertNativeToUnicode(String, String)
       */
      public static String convertUnicodeToNative(String source, String charset)
          throws IOException
      {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          OutputStreamWriter out = new OutputStreamWriter(baos, charset);
          out.write(source);
          out.close();
          return baos.toString();
      }
  
      /**
       * Convert a string from a native encoding to unicode.  This
       * method is generally used to create a <code>String</code> for
       * use as input, and is useful when dealing with I18N.
       *
       * @param input String the input to convert from native encoding
       * to unicode.
       * @param charset String the charset from which to convert.
       * @return The string given represented in unicode rather than the
       * specified native encoding.
       */
      public static String convertNativeToUnicode(String input, String charset)
          throws IOException
      {
          InputStreamReader in = new InputStreamReader
              (new ByteArrayInputStream(input.getBytes()), charset);
          StringBuffer output = new StringBuffer();
          char[] buf = new char[CHAR_BUFFER_SIZE];
          int count = 0;
          while ((count = in.read(buf, 0, CHAR_BUFFER_SIZE)) > 0)
          {
              output.append(buf, 0, count);
          }
          in.close();
          return output.toString();
      }
  }
  
  
  /**
   * A range of characters. Able to understand the idea of a contiguous 
   * sublist of an alphbet, a negated concept, and a set of characters.
   * Used by StringUtil to handle sets of characters.
   *
   * @author bayard@generationjava.com
   * @version 0.4 20010812
   */
  class CharRange {
  
      /**
       * Used internally to represent null in a char.
       */
      static private char UNSET;
  
      private char start;
      private char close;
      private boolean negated;
  
      /**
       * Construct a CharRange over a single character.
       *
       * @param start char over which this range is placed
       */
      public CharRange(char start) {
          this.start = start;
      }
  
      /**
       * Construct a CharRange over a set of characters.
       *
       * @param start char start character in this range. inclusive
       * @param close char close character in this range. inclusive
       */
      public CharRange(char start, char close) {
          this.start = start;
          this.close = close;
      }
  
      /**
       * Construct a CharRange over a set of characters.
       *
       * @param start String start first character is in this range (inclusive).
       * @param close String first character is close character in this
       * range (inclusive).
       */
      public CharRange(String start, String close) {
          this.start = start.charAt(0);
          this.close = close.charAt(0);
      }
  
      public char getStart() {
          return this.start;
      }
  
      public char getEnd() {
          return this.close;
      }
  
      public void setStart(char ch) {
          this.start = ch;
      }
  
      public void setEnd(char ch) {
          this.close = ch;
      }
  
      /**
       * Is this CharRange over many characters
       *
       * @return boolean true is many characters
       */
      public boolean isRange() {
          return this.close != UNSET;
      }
  
      /**
       * Is the passed in character inside this range
       *
       * @return boolean true is in range
       */
      public boolean inRange(char ch) {
          if(isRange()) {
              return ((ch >= start) && (ch <= close) );
          } else {
              return start == ch;
          }
      }
  
      /**
       * Is this CharRange negated
       *
       * @return boolean true is negated
       */
      public boolean isNegated() {
          return negated;
      }
  
      /**
       * Make this character range be negated. 
       * This implies that this CharRange is over all characters except 
       * the ones in this range.
       */
      public void setNegated(boolean b) {
          this.negated = b;
      }
  
      public String toString() {
          String str = "";
          if(isNegated()) {
              str += "^";
          }
          str += start;
          if(isRange()) {
              str += "-";
              str += close;
          }
          return str;
      }
  }
  
  
  
  /**
   * A set of characters. You can iterate over the characters in the 
   * set.
   *
   * @author bayard@generationjava.com
   * @version 0.4 20010812
   */
  class CharSet {
  
      // used to be a com.generationjava.collections.typed.TypedList
      private LinkedList set = new LinkedList();
  
      public CharSet(String[] set) {
          int sz = set.length;
          for(int i=0; i<sz; i++) {
              add(set[i]);
          }
      }
  
      public boolean contains(char ch) {
          Iterator iterator = set.iterator();
          boolean bool = false;
          while(iterator.hasNext()) {
              CharRange range = (CharRange)iterator.next();
              if(range.isNegated()) {
                  if(!range.inRange(ch)) {
                      bool = true;
                  }
              } else {
                  if(range.inRange(ch)) {
                      bool = true;
                  }
              }
          }
          return bool;
      }
  
      public void add(String str) {
          int sz = str.length();
          CharRange range = null;
          boolean end = false;
          boolean negated = false;
          for(int i=0; i<sz; i++) {
              char ch = str.charAt(i);
              if(ch == '-') {
                  end = true;
                  continue;
              }
              if(end) {
                  range.setEnd(ch);
                  continue;
              }
              if(ch == '^') {
                  negated = true;
                  continue;
              }
              range = new CharRange(ch);
              range.setNegated(negated);
              set.add(range);
          }
      }
  
      public String toString() {
          return set.toString();
      }
  
  }
  
  
  
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/Nestable.java
  
  Index: Nestable.java
  ===================================================================
  package org.apache.commons.lang.exception;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.PrintWriter;
  
  /**
   * An interface to be implemented by {@link java.lang.Throwable}
   * extensions which would like to be able to nest root exceptions
   * inside themselves.
   *
   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
   * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
   */
  public interface Nestable
  {
      /**
       * Returns the reference to the exception or error that caused the
       * exception implementing the <code>Nestable</code> to be thrown.
       */
      public Throwable getCause();
  
      /**
       * Returns the error message of this and any nested
       * <code>Throwable</code>.
       *
       * @return The error message.
       */
      public String getMessage();
  
      /**
       * Prints the stack trace of this exception to the specified print
       * writer.  Includes inforamation from the exception--if
       * any--which caused this exception.
       *
       * @param out <code>PrintWriter</code> to use for output.
       */
      public void printStackTrace(PrintWriter out);
  
      /**
       * Prints the stack trace for this exception only--root cause not
       * included--using the provided writer.  Used by {@link
       * org.apache.commons.lang.exception.NestableDelegate} to write
       * individual stack traces to a buffer.  The implementation of
       * this method should call
       * <code>super.printStackTrace(out);</code> in most cases.
       *
       * @param out The writer to use.
       */
      public void printPartialStackTrace(PrintWriter out);
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableDelegate.java
  
  Index: NestableDelegate.java
  ===================================================================
  package org.apache.commons.lang.exception;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.OutputStream;
  import java.io.PrintStream;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.io.Writer;
  import java.util.LinkedList;
  import java.util.StringTokenizer;
  
  /**
   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
   * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
   */
  public class NestableDelegate
  {
      /**
       * Constructor error message.
       */
      private static final String MUST_BE_THROWABLE =
          "The Nestable implementation passed to the NestableDelegate(Nestable) "
          + "constructor must extend java.lang.Throwable";
  
      /**
       * Holds the reference to the exception or error that caused
       * this exception to be thrown.
       */
      private Nestable cause = null;
  
      /**
       * @param cause The Nestable implementation to get a stack trace for
       * (<i>must</i> extend {@link java.lang.Throwable}).
       */
      public NestableDelegate(Nestable cause)
      {
          if (cause instanceof Throwable)
          {
              this.cause = cause;
          }
          else
          {
              throw new IllegalArgumentException(MUST_BE_THROWABLE);
          }
      }
  
      /**
       * @param baseMsg The base message to use when creating the full
       * message.  Should be generally be called via
       * <code>nestableHelper.getMessage(super.getMessage())</code>,
       * where <code>super</code> is an instance of {@link
       * java.lang.Throwable}.
       * @return The concatenated message for this and all nested
       * exceptions.
       */
      public String getMessage(String baseMsg)
      {
          StringBuffer msg = new StringBuffer();
          if (baseMsg != null)
          {
              msg.append(baseMsg);
          }
  
          Throwable nestedCause = cause.getCause();
          if (nestedCause != null)
          {
              String causeMsg = nestedCause.getMessage();
              if (causeMsg != null)
              {
                  if (baseMsg != null)
                  {
                      msg.append(": ");
                  }
                  msg.append(causeMsg);
              }
  
          }
          return (msg.length() > 0 ? msg.toString() : null);
      }
  
      /**
       * Prints the stack trace of this exception the the standar error
       * stream.
       */
      public void printStackTrace()
      {
          synchronized (System.err)
          {
              printStackTrace(System.err);
          }
      }
  
      /**
       * Prints the stack trace of this exception to the specified print stream.
       *
       * @param out <code>PrintStream</code> to use for output.
       */
      public void printStackTrace(PrintStream out)
      {
          synchronized (out)
          {
              PrintWriter pw = new PrintWriter(out, false);
              printStackTrace(pw);
              // Flush the PrintWriter before it's GC'ed.
              pw.flush();
          }
      }
  
      /**
       * Prints the stack trace of this exception to the specified print writer.
       *
       * @param out <code>PrintWriter</code> to use for output.
       */
      public void printStackTrace(PrintWriter out)
      {
          synchronized (out)
          {
              String[] st = decompose((Throwable) cause);
              Throwable nestedCause = cause.getCause();
              if (nestedCause != null)
              {
                  if (nestedCause instanceof Nestable)
                  {
                      // Recurse until a non-Nestable is encountered.
                      ((Nestable) nestedCause).printStackTrace(out);
                  }
                  else
                  {
                      String[] nst = decompose(nestedCause);
                      for (int i = 0; i < nst.length; i++)
                      {
                          out.println(nst[i]);
                      }
                  }
                  out.print("rethrown as ");
              }
  
              // Output desired frames from stack trace.
              for (int i = 0; i < st.length; i++)
              {
                  out.println(st[i]);
              }
          }
      }
  
      /**
       * Captures the stack trace associated with a <code>Throwable</code>
       * object, decomposing it into a list of stack frames.
       *
       * @param t The <code>Throwable</code>.
       * @return  An array of strings describing each stack frame.
       */
      private String[] decompose(Throwable t)
      {
          StringWriter sw = new StringWriter();
          PrintWriter pw = new PrintWriter(sw, true);
  
          // Avoid infinite loop between decompose() and printStackTrace().
          if (t instanceof Nestable)
          {
              ((Nestable) t).printPartialStackTrace(pw);
          }
          else
          {
              t.printStackTrace(pw);
          }
  
          String linebreak = System.getProperty("line.separator");
          StringTokenizer st = new StringTokenizer(sw.getBuffer().toString(),
                                                   linebreak);
          LinkedList list = new LinkedList();
          while (st.hasMoreTokens())
          {
              list.add(st.nextToken());
          }
          return (String []) list.toArray(new String[] {});
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableException.java
  
  Index: NestableException.java
  ===================================================================
  package org.apache.commons.lang.exception;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.OutputStream;
  import java.io.PrintStream;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.io.Writer;
  import java.util.LinkedList;
  import java.util.StringTokenizer;
  
  /**
   * The base class of all exceptions which can contain other exceptions.
   *
   * It is intended to ease the debugging by carrying on the information
   * about the exception which was caught and provoked throwing the
   * current exception. Catching and rethrowing may occur multiple
   * times, and provided that all exceptions except the first one
   * are descendands of <code>NestedException</code>, when the
   * exception is finally printed out using any of the <code>
   * printStackTrace()</code> methods, the stacktrace will contain
   * the information about all exceptions thrown and caught on
   * the way.
   * <p> Running the following program
   * <p><blockquote><pre>
   *  1 import org.apache.commons.NestedException;
   *  2
   *  3 public class Test {
   *  4     public static void main( String[] args ) {
   *  5         try {
   *  6             a();
   *  7         } catch(Exception e) {
   *  8             e.printStackTrace();
   *  9         }
   * 10      }
   * 11
   * 12      public static void a() throws Exception {
   * 13          try {
   * 14              b();
   * 15          } catch(Exception e) {
   * 16              throw new NestedException("foo", e);
   * 17          }
   * 18      }
   * 19
   * 20      public static void b() throws Exception {
   * 21          try {
   * 22              c();
   * 23          } catch(Exception e) {
   * 24              throw new NestedException("bar", e);
   * 25          }
   * 26      }
   * 27
   * 28      public static void c() throws Exception {
   * 29          throw new Exception("baz");
   * 30      }
   * 31 }
   * </pre></blockquote>
   * <p>Yields the following stacktrace:
   * <p><blockquote><pre>
   * java.lang.Exception: baz: bar: foo
   *    at Test.c(Test.java:29)
   *    at Test.b(Test.java:22)
   * rethrown as NestedException: bar
   *    at Test.b(Test.java:24)
   *    at Test.a(Test.java:14)
   * rethrown as NestedException: foo
   *    at Test.a(Test.java:16)
   *    at Test.main(Test.java:6)
   * </pre></blockquote><br>
   *
   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
   * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
   */
  public class NestableException extends Exception implements Nestable
  {
      /**
       * The helper instance which contains much of the code which we
       * delegate to.
       */
      protected NestableDelegate delegate = new NestableDelegate(this);
  
      /**
       * Holds the reference to the exception or error that caused
       * this exception to be thrown.
       */
      private Throwable cause = null;
  
      /**
       * Constructs a new <code>NestableException</code> without specified
       * detail message.
       */
      public NestableException()
      {
          super();
      }
  
      /**
       * Constructs a new <code>NestableException</code> with specified
       * detail message.
       *
       * @param msg The error message.
       */
      public NestableException(String msg)
      {
          super(msg);
      }
  
      /**
       * Constructs a new <code>NestableException</code> with specified
       * nested <code>Throwable</code>.
       *
       * @param nested The exception or error that caused this exception
       *               to be thrown.
       */
      public NestableException(Throwable cause)
      {
          super();
          this.cause = cause;
      }
  
      /**
       * Constructs a new <code>NestableException</code> with specified
       * detail message and nested <code>Throwable</code>.
       *
       * @param msg    The error message.
       * @param nested The exception or error that caused this exception
       *               to be thrown.
       */
      public NestableException(String msg, Throwable cause)
      {
          super(msg);
          this.cause = cause;
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#getCause()
       */
      public Throwable getCause()
      {
          return cause;
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#getMessage()
       */
      public String getMessage()
      {
          StringBuffer msg = new StringBuffer();
          String ourMsg = super.getMessage();
          if (ourMsg != null)
          {
              msg.append(ourMsg);
          }
          if (cause != null)
          {
              String causeMsg = cause.getMessage();
              if (causeMsg != null)
              {
                  if (ourMsg != null)
                  {
                      msg.append(": ");
                  }
                  msg.append(causeMsg);
              }
  
          }
          return (msg.length() > 0 ? msg.toString() : null);
      }
  
      /**
       * Prints the stack trace of this exception the the standar error
       * stream.
       */
      public void printStackTrace()
      {
          delegate.printStackTrace();
      }
  
      /**
       * Prints the stack trace of this exception to the specified print stream.
       *
       * @param out <code>PrintStream</code> to use for output.
       */
      public void printStackTrace(PrintStream out)
      {
          delegate.printStackTrace(out);
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#printStackTrace(PrintWriter out)
       */
      public void printStackTrace(PrintWriter out)
      {
          delegate.printStackTrace(out);
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#printPartialStackTrace(PrintWriter out)
       */
      public final void printPartialStackTrace(PrintWriter out)
      {
          super.printStackTrace(out);
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableRuntimeException.java
  
  Index: NestableRuntimeException.java
  ===================================================================
  package org.apache.commons.lang.exception;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  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.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Turbine" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
   * ITS 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 consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.OutputStream;
  import java.io.PrintStream;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.io.Writer;
  import java.util.LinkedList;
  import java.util.StringTokenizer;
  
  /**
   * The base class of all runtime exceptions which can contain other
   * exceptions.
   *
   * @see org.apache.commons.lang.exception.NestableException
   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
   * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
   */
  public class NestableRuntimeException extends RuntimeException
      implements Nestable
  {
      /**
       * The helper instance which contains much of the code which we
       * delegate to.
       */
      protected NestableDelegate delegate = new NestableDelegate(this);
  
      /**
       * Holds the reference to the exception or error that caused
       * this exception to be thrown.
       */
      private Throwable cause = null;
  
      /**
       * Constructs a new <code>NestableRuntimeException</code> without specified
       * detail message.
       */
      public NestableRuntimeException()
      {
          super();
      }
  
      /**
       * Constructs a new <code>NestableRuntimeException</code> with specified
       * detail message.
       *
       * @param msg The error message.
       */
      public NestableRuntimeException(String msg)
      {
          super(msg);
      }
  
      /**
       * Constructs a new <code>NestableRuntimeException</code> with specified
       * nested <code>Throwable</code>.
       *
       * @param nested The exception or error that caused this exception
       *               to be thrown.
       */
      public NestableRuntimeException(Throwable cause)
      {
          super();
          this.cause = cause;
      }
  
      /**
       * Constructs a new <code>NestableRuntimeException</code> with specified
       * detail message and nested <code>Throwable</code>.
       *
       * @param msg    The error message.
       * @param nested The exception or error that caused this exception
       *               to be thrown.
       */
      public NestableRuntimeException(String msg, Throwable cause)
      {
          super(msg);
          this.cause = cause;
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#getCause()
       */
      public Throwable getCause()
      {
          return cause;
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#getMessage()
       */
      public String getMessage()
      {
          StringBuffer msg = new StringBuffer();
          String ourMsg = super.getMessage();
          if (ourMsg != null)
          {
              msg.append(ourMsg);
          }
          if (cause != null)
          {
              String causeMsg = cause.getMessage();
              if (causeMsg != null)
              {
                  if (ourMsg != null)
                  {
                      msg.append(": ");
                  }
                  msg.append(causeMsg);
              }
  
          }
          return (msg.length() > 0 ? msg.toString() : null);
      }
  
      /**
       * Prints the stack trace of this exception the the standar error
       * stream.
       */
      public void printStackTrace()
      {
          delegate.printStackTrace();
      }
  
      /**
       * Prints the stack trace of this exception to the specified print stream.
       *
       * @param out <code>PrintStream</code> to use for output.
       */
      public void printStackTrace(PrintStream out)
      {
          delegate.printStackTrace(out);
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#printStackTrace(PrintWriter out)
       */
      public void printStackTrace(PrintWriter out)
      {
          delegate.printStackTrace(out);
      }
  
      /**
       * @see org.apache.commons.lang.exception.Nestable#printPartialStackTrace(PrintWriter out)
       */
      public final void printPartialStackTrace(PrintWriter out)
      {
          super.printStackTrace(out);
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception Nestable.java NestableDelegate.java NestableException.java NestableRuntimeException.java

Posted by ba...@generationjava.com.
Note: Strings.java had two dependencies. One on CollectionsUtils and one
on FileUtils. The CollectionsUtils was for a small reverseArray method.
This may be better placed in lang anyway, but for the moment I made it a
private method of Strings. The FileUtils dependency was on
FileUtils.ONE_KB. I hardcoded this as 1024.

This is used by some string encoding methods in Strings. These may be
better placed in codec.

On 22 Feb 2002 bayard@apache.org wrote:

> bayard      02/02/21 21:57:15
>
>   Added:       lang/src/java/org/apache/commons/lang Classes.java
>                         Numbers.java Objects.java Strings.java
>                lang/src/java/org/apache/commons/lang/exception
>                         Nestable.java NestableDelegate.java
>                         NestableException.java
>                         NestableRuntimeException.java
>   Log:
>   Initial commit of 'lang' classes from Commons.Utils.
>
>   Revision  Changes    Path
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Classes.java
>
>   Index: Classes.java
>   ===================================================================
>   package org.apache.commons.lang;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Commons" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   /**
>    * A set of static utilities for use with Classes.
>    *
>    * @author  bayard@generationjava.com
>    * @version $Id: Classes.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
>    */
>   final public class Classes {
>
>       /**
>        * Create an object from the classname. Must have an empty constructor.
>        *
>        * @param classname String name of the class
>        *
>        * @return Object instance of the class or null
>        */
>       static public Object createObject(String classname) {
>           Class tmpClass = null;
>
>           tmpClass = getClass(classname);
>
>           return createObject(tmpClass);
>       }
>
>       /**
>        * Create an object from a class.
>        *
>        * @param clss Class object to instantiate
>        *
>        * @return Object instance of the class or null
>        */
>       static public Object createObject(Class clss) {
>
>           try {
>               return clss.newInstance();
>           } catch (IllegalAccessException  iae) {
>               System.err.println("Cant instantiate " + clss.getName() + " because " +
>                      iae.getMessage());
>           } catch (InstantiationException  ie) {
>               System.err.println("Cant instantiate " + clss.getName() + " because " +
>                      ie.getMessage());
>           }
>
>           return null;
>       }
>
>       /**
>        * Is this Class in the CLASSPATH
>        *
>        * @param classname String of the class
>        *
>        * @return boolean exists or not.
>        */
>       static public boolean classExists(String classname) {
>           Class tmpClass = null;
>
>           /* try and load class */
>           try {
>               tmpClass = Class.forName(classname);
>           } catch (ClassNotFoundException cnfe) {
>               return false;
>           } catch (IllegalArgumentException iae) {
>               return false;
>           }
>
>           return true;
>       }
>
>       /**
>        * Get the Class object for a classname.
>        *
>        * @param classname String of the class
>        *
>        * @return Class instance for the class.
>        */
>       static public Class getClass(String classname) {
>           Class tmpClass = null;
>
>           /* try an load class */
>           try {
>               tmpClass = Class.forName(classname);
>           } catch (ClassNotFoundException cnfe) {
>               System.out.println("Can't resolve classname " + classname);
>           } catch (IllegalArgumentException iae) {
>               System.err.println("Cant resolve " + tmpClass.getName() + " because " + iae.getMessage());
>           }
>
>           return tmpClass;
>       }
>
>       /**
>        * Is this Class object an instance of the class with this name.
>        *
>        * @param clss Class instance
>        * @param inst String name of potential supertype
>        *
>        * @return boolean was it an instanceof
>        */
>       static public boolean classInstanceOf(Class clss, String inst) {
>           if(classImplements(clss,inst)) {
>               return true;
>           } else
>           if(classExtends(clss,inst)) {
>               return true;
>           } else {
>               return false;
>           }
>       }
>
>       /**
>        * Does this Class implement an interface with this name.
>        *
>        * @param clss Class instance
>        * @param exts String name of potential interface
>        *
>        * @return boolean was it an implementor
>        */
>       static public boolean classImplements(Class clss, String exts) {
>
>         Class sprcls = clss;
>         Class excls  = getClass(exts);
>
>         while(sprcls != null) {
>           Class[] interfaces = sprcls.getInterfaces();
>
>           for(int i=0;i<interfaces.length;i++) {
>               if(interfaces[i].equals(excls)) {
>                   return true;
>               }
>           }
>
>           sprcls = sprcls.getSuperclass();
>         }
>
>         return false;
>       }
>
>       /**
>        * Does this Class extend a superclass with this name.
>        *
>        * @param clss Class instance
>        * @param exts String name of potential superclass
>        *
>        * @return boolean was it a superclass
>        */
>       static public boolean classExtends(Class clss, String exts) {
>           if(clss == null) {
>               return false;
>           }
>           if(clss.getName().equals(exts)) {
>               return true;
>           }
>           Class sprcls = clss.getSuperclass();
>           Class excls = getClass(exts);
>
>   //        while(! sprcls.equals(sprcls.getSuperclass()) ) {
>           while( sprcls != null ) {
>               if(sprcls.equals(excls)) {
>                   return true;
>               }
>               sprcls = sprcls.getSuperclass();
>           }
>           return false;
>       }
>
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Numbers.java
>
>   Index: Numbers.java
>   ===================================================================
>   package org.apache.commons.lang;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Commons" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.math.BigInteger;
>   import java.math.BigDecimal;
>
>   /**
>    * Provides extra functionality for java Number classes.
>    *
>    * @author bayard@generationjava.com
>    * @version $Id: Numbers.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
>    */
>   final public class Numbers {
>
>       static public int stringToInt(String str) {
>           return stringToInt(str,0);
>       }
>       static public int stringToInt(String str, int def) {
>           try {
>               return Integer.parseInt(str);
>           } catch(NumberFormatException nfe) {
>               return def;
>           }
>       }
>
>       // must handle Long, Float, Integer, Float, Short,
>       //                  BigDecimal, BigInteger and Byte
>       // useful methods:
>       // Byte.decode(String)
>       // Byte.valueOf(String,int radix)
>       // Byte.valueOf(String)
>       // Double.valueOf(String)
>       // Float.valueOf(String)
>       // new Float(String)
>       // Integer.valueOf(String,int radix)
>       // Integer.valueOf(String)
>       // Integer.decode(String)
>       // Integer.getInteger(String)
>       // Integer.getInteger(String,int val)
>       // Integer.getInteger(String,Integer val)
>       // new Integer(String)
>       // new Double(String)
>       // new Byte(String)
>       // new Long(String)
>       // Long.getLong(String)
>       // Long.getLong(String,int)
>       // Long.getLong(String,Integer)
>       // Long.valueOf(String,int)
>       // Long.valueOf(String)
>       // new Short(String)
>       // Short.decode(String)
>       // Short.valueOf(String,int)
>       // Short.valueOf(String)
>       // new BigDecimal(String)
>       // new BigInteger(String)
>       // new BigInteger(String,int radix)
>       // Possible inputs:
>       // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
>       // plus minus everything. Prolly more. A lot are not separable.
>
>       /**
>        * Turns a string value into a java.lang.Number.
>        * Strategy is to look for a decimal point. If that is seen then
>        * try first float and then try double.
>        * If this fails, then try int and then long.
>        * Assuming 50f fails and isn't 50, then try hexadecimal.
>        *
>        * @param val String containing a number
>        *
>        * @return Number created from the string
>        */
>       static public Number createNumber(String val)
>               throws NumberFormatException
>       {
>           if (val == null) {
>               return null;
>           }
>
>           int idx = val.indexOf('.');
>           if ( (idx != -1) && (idx != val.length()-1) )  {
>               try {
>                   return createFloat(val);
>               } catch (NumberFormatException nfe) {
>               }
>               try {
>                   return createDouble(val);
>               } catch (NumberFormatException nfe) {
>               }
>
>               // look for all digits or '.' with f or F on end.
>               if( val.endsWith("f") || val.endsWith("F") ) {
>                   String mant = val.substring(0,idx);
>                   String dec = val.substring(idx+1,val.length()-1);
>                   if(containsDigits(mant) && containsDigits(dec) ) {
>                       try {
>                           return createFloat(val.substring(0,val.length()-1));
>                       } catch (NumberFormatException nfe) {
>                       }
>                   }
>               }
>
>               // look for all digits or '.' with d or D on end.
>               if( val.endsWith("d") || val.endsWith("D") ) {
>                   String mant = val.substring(0,idx);
>                   String dec = val.substring(idx+1,val.length()-1);
>                   if(containsDigits(mant) && containsDigits(dec) ) {
>                       try {
>                           return createDouble(val.substring(0,val.length()-1));
>                       } catch (NumberFormatException nfe) {
>                       }
>                   }
>               }
>
>               try {
>                   return createBigDecimal(val);
>               } catch (NumberFormatException nfe) {
>               }
>
>               throw new NumberFormatException("Unable to convert: "+val);
>           }
>
>           try {
>               return createInteger(val);
>           } catch (NumberFormatException nfe) {
>           }
>           try {
>               return createLong(val);
>           } catch (NumberFormatException nfe) {
>           }
>
>
>           // look for all digits with l or L on the end.
>           if( val.endsWith("l") || val.endsWith("L") ) {
>               if(containsDigits(val.substring(0,val.length()-1))) {
>                   try {
>                       return createLong(val.substring(0,val.length()-1));
>                   } catch (NumberFormatException nfe) {
>                   }
>               }
>           }
>
>
>           try {
>               return createBigInteger(val);
>           } catch (NumberFormatException nfe) {
>           }
>
>           // try Hex.
>           try {
>               return Integer.valueOf(val,16);
>           } catch (NumberFormatException nfe) {
>           }
>
>           throw new NumberFormatException("Unable to convert: "+val);
>       }
>
>       /**
>        * Return true if the string contains only digit characters.
>        *
>        * @param val String to check is only digits
>        *
>        * @return boolean contains only unicode numeric
>        */
>       static public boolean containsDigits(String val) {
>           if(val == null) {
>               return false; // ???
>           }
>           for(int i=0;i<val.length();i++) {
>               if(!Character.isDigit(val.charAt(i))) {
>                   return false;
>               }
>           }
>           return true;
>       }
>
>       static public Float createFloat(String val) {
>           return Float.valueOf(val);
>       }
>
>       static public Double createDouble(String val) {
>           return Double.valueOf(val);
>       }
>
>       // handles 0xAABD and 0777 (hex and octal) as well.
>       static public Integer createInteger(String val) {
>           // return Integer.valueOf(val);
>           return Integer.decode(val);
>       }
>
>       static public Long createLong(String val) {
>           return Long.valueOf(val);
>       }
>
>       static public BigInteger createBigInteger(String val) {
>           BigInteger bi = new BigInteger(val);
>           return bi;
>       }
>
>       static public BigDecimal createBigDecimal(String val) {
>           BigDecimal bd = new BigDecimal(val);
>           return bd;
>       }
>
>       /**
>        * Get the minimum of three values.
>        */
>       static public int minimum(int a, int b, int c) {
>           if(b < a) {
>               a = b;
>           }
>           if(c < a) {
>               a = c;
>           }
>           return a;
>       }
>
>       /**
>        * Is a String a valid Java number.
>        * Doesn't allow scientific notation.
>        */
>       static public boolean isNumber(String str) {
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length;
>           boolean decimal = false;
>           for(int i=0; i<sz; i++) {
>               // possibly faster as a continuous switch
>               if( (chrs[i] >= '0') && (chrs[i] <= '9') ) {
>                   continue;
>               }
>               if(i==0) {
>                   if(chrs[i] == '-') {
>                       continue;
>                   }
>               }
>               if(chrs[i] == '.') {
>                   if(!decimal) {
>                       decimal = true;
>                       continue;
>                   }
>               }
>               return false;
>           }
>           return true;
>       }
>
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Objects.java
>
>   Index: Objects.java
>   ===================================================================
>   package org.apache.commons.lang;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.BufferedInputStream;
>   import java.io.ByteArrayInputStream;
>   import java.io.IOException;
>   import java.io.InputStream;
>   import java.io.ObjectInputStream;
>
>   /**
>    * Common <code>Object</code> manipulation routines.
>    *
>    * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
>    * @author <a href="mailto:janekdb@yahoo.co.uk">Janek Bogucki</a>
>    * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
>    * @version $Id: Objects.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
>    */
>   public class Objects
>   {
>       /**
>        * Returns a default value if the object passed is null.
>        *
>        * @param o The object to test.
>        * @param dflt The default value to return.
>        * @return The object o if it is not null, dflt otherwise.
>        */
>       public static Object isNull(Object o, Object dflt)
>       {
>           return (o != null ? o : dflt);
>       }
>
>       /**
>        * Deserializes a single object from an array of bytes.
>        *
>        * @param objectData The serialized object.
>        * @return The deserialized object, or <code>null</code> on failure.
>        */
>       public static Object deserialize(byte[] objectData)
>       {
>           Object object = null;
>           if (objectData != null)
>           {
>               ObjectInputStream in = null;
>               try
>               {
>                   InputStream bin = new ByteArrayInputStream(objectData);
>                   in = new ObjectInputStream(bin);
>
>                   // If objectData has not been initialized, an
>                   // exception will occur.
>                   object = in.readObject();
>               }
>               catch (Exception returnNull)
>               {
>               }
>               finally
>               {
>                   try
>                   {
>                       if (in != null)
>                       {
>                           in.close();
>                       }
>                   }
>                   catch (IOException ignored)
>                   {
>                   }
>               }
>           }
>           return object;
>       }
>
>       /**
>        * Compares two objects for equality, where either one or both
>        * objects may be <code>null</code>.
>        *
>        * @param o1 The first object.
>        * @param o2 The second object.
>        * @return True if the values of both objects are the same.
>        */
>       public static boolean equals(Object o1, Object o2)
>       {
>           if (o1 == null)
>           {
>               return (o2 == null);
>           }
>           else if (o2 == null)
>           {
>               // o1 is not null
>               return false;
>           }
>           else
>           {
>               return o1.equals(o2);
>           }
>       }
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/Strings.java
>
>   Index: Strings.java
>   ===================================================================
>   package org.apache.commons.lang;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.ByteArrayInputStream;
>   import java.io.ByteArrayOutputStream;
>   import java.io.InputStreamReader;
>   import java.io.OutputStreamWriter;
>   import java.io.OutputStream;
>   import java.io.PrintWriter;
>   import java.io.IOException;
>   import java.util.NoSuchElementException;
>   import java.util.StringTokenizer;
>
>   import java.util.Iterator;
>   import java.util.Map;
>   import java.util.Random;
>
>   // CharSet
>   import java.util.List;
>   import java.util.LinkedList;
>
>
>   /**
>    * <p>Common <code>String</code> manipulation routines.</p>
>    *
>    * <p>Originally from <a
>    * href="http://jakarta.apache.org/turbine/">Turbine</a> and the
>    * GenerationJavaCore library.</p>
>    *
>    * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
>    * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
>    * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
>    * @author <a href="mailto:bayard@generationjava.com">Bayard</a>
>    * @author <a href="mailto:ed@apache.org">Ed Korthof</a>
>    * @version $Id: Strings.java,v 1.1 2002/02/22 05:57:15 bayard Exp $
>    */
>   public class Strings
>   {
>       /**
>        * The size of the buffer to use when working with I/O (4 kB).
>        */
>       //public static int CHAR_BUFFER_SIZE = 4 * FileUtils.ONE_KB;
>       public static int CHAR_BUFFER_SIZE = 4 * 1024;
>
>       /**
>        * Trims text safely, dealing with <code>null</code> references by
>        * converting them to <code>""</code> (the empty string).
>        *
>        * @param s The text to trim.
>        * @return The trimmed text (never <code>null</code>).
>        */
>       public static final String clean(String s)
>       {
>           return (s == null ? "" : s.trim());
>       }
>
>       /**
>        * Trims text safely, dealing with <code>null</code> references by
>        * returning <code>null</code> (rather than throwing a
>        * NullPointerException).
>        *
>        * @param s The text to trim.
>        * @return The trimmed text (or <code>null</code>).
>        */
>       public static final String trim(String s)
>       {
>           return (s == null ? null : s.trim());
>       }
>
>       /**
>        * Validates that the supplied string is neither <code>null</code>
>        * nor the empty string.
>        *
>        * @param text The text to check.
>        * @return Whether valid.
>        */
>       public static final boolean isValid(String text)
>       {
>           return (text != null && text.length() > 0);
>       }
>
>       /**
>        * Determine whether a (trimmed) string is empty
>        *
>        * @param foo The text to check.
>        * @return Whether empty.
>        */
>       public static final boolean isEmpty(String foo)
>       {
>           return (foo == null || foo.trim().length() == 0);
>       }
>
>       /**
>        * Returns the output of printStackTrace as a String.
>        *
>        * @param e The source to extract a stack trace from.
>        * @return The extracted stack trace.
>        */
>       public static final String stackTrace(Throwable e)
>       {
>           String trace = null;
>           try
>           {
>               // And show the Error Screen.
>               ByteArrayOutputStream buf = new ByteArrayOutputStream();
>               e.printStackTrace( new PrintWriter(buf, true) );
>               trace = buf.toString();
>           }
>           catch (Exception ignored)
>           {
>           }
>           return trace;
>       }
>
>       /**
>        * Safely compares two <code>String</code> objects, returning
>        * whether their values are the same.  Two <code>null</code>
>        * references are considered equal.
>        *
>        * @param s1 The first string.
>        * @param s2 The second string.
>        * @return Whether the values of both strings are the same.
>        */
>       public static boolean equals(String s1, String s2)
>       {
>           return (s1 == null ? s2 == null : s1.equals(s2));
>       }
>
>       /**
>        * Takes a String of the form <code>substring[substring]substring</code>
>        * and returns the three parsed substrings.
>        *
>        * @return A three element {@link java.lang.String} array populated by
>        * any parsed object key components.
>        */
>       public static String[] parseObjectKey(String s)
>       {
>           String[] objectKey = new String[3];
>           StringTokenizer st = new StringTokenizer(s, "[]");
>           int count = st.countTokens();
>           if (count > 1)
>           {
>               objectKey[0] = st.nextToken();
>               objectKey[1] = st.nextToken();
>               if (count == 3)
>               {
>                   objectKey[2] = st.nextToken();
>               }
>           }
>           return objectKey;
>       }
>
>       /**
>        * Removes underscores from text.
>        *
>        * @param text The text to remove any underscores from.
>        * @return The underscore-less text.
>        * @deprecated Use replace(String, String, String) instead.
>        */
>       public static String removeUnderScores(String text)
>       {
>           return replace(text, "_", "", -1);
>       }
>
>       /**
>        * Makes the first letter capital and leaves the rest as is.
>        *
>        * @param text The text to modify.
>        * @return The modified text.
>        */
>       public static String firstLetterCaps(String text)
>       {
>           return (text == null ? null :
>                   text.substring(0, 1).toUpperCase() + text.substring(1));
>       }
>
>       /**
>        * @see #split(String text, String separator, int max)
>        */
>       public static String[] split(String text)
>       {
>           return split(text, " ", -1);
>       }
>
>       /**
>        * @see #split(String text, String separator, int max)
>        */
>       public static String[] split(String text, String separator)
>       {
>           return split(text, separator, -1);
>       }
>
>       /**
>        * Splits the provided text into a list, based on a given
>        * separator.
>        *
>        * @param text Textual list to parse.
>        * @param separator The separator character.
>        * @param max The maximum number of elements to include in the
>        * list.  A value of <code>-1</code> implies no limit.
>        * @return The list of values.
>        */
>       public static String[] split(String text, String separator, int max)
>       {
>           StringTokenizer tok = new StringTokenizer(text, separator);
>           int listSize = tok.countTokens();
>           if (max != -1 && listSize > max)
>           {
>               listSize = max;
>           }
>
>           String[] list = new String[listSize];
>           int i = 0;
>           while (tok.hasMoreTokens())
>           {
>               if (max != -1 && i == listSize - 1)
>               {
>                   // In the situation where we hit the max yet have
>                   // tokens left over in our input, the last list
>                   // element gets all remaining text.
>                   StringBuffer buf = new StringBuffer
>                       ((int) 1.2 * text.length() * (listSize - i) / listSize);
>                   while (tok.hasMoreTokens())
>                   {
>                       buf.append(tok.nextToken());
>                       if (tok.hasMoreTokens())
>                       {
>                           buf.append(separator);
>                       }
>                   }
>                   list[i] = buf.toString();
>                   break;
>               }
>               else
>               {
>                   list[i] = tok.nextToken();
>               }
>               i++;
>           }
>           return list;
>       }
>
>       /**
>        * Joins the elements of the provided array into a single string
>        * containing the provided list of elements.  No delimiter is
>        * added before or after the list.
>        *
>        * @param list      The list of values to join together.
>        * @param separator The separator character.
>        * @return          The CSV text.
>        */
>       public static String join(Object[] list, String separator)
>       {
>           int listSize = list.length;
>           int bufSize = (listSize == 0 ? 0 :(list[0].toString().length() +
>                                              separator.length()) * listSize);
>           StringBuffer buf = new StringBuffer(bufSize);
>
>           for (int i = 0; i < listSize; i++)
>           {
>               if (i > 0)
>               {
>                   buf.append(separator);
>               }
>               buf.append(list[i]);
>           }
>           return buf.toString();
>       }
>
>       /**
>        * Merges the list of <code>Object</code> intances supplied by an
>        * <code>Iterator</code> into a single piece text.  No delimiter
>        * is added before or after the list.
>        *
>        * @param iterator The list provider.
>        * @param separator String delimiter to separate list elements
>        * with.
>        * @return Text delimited list as a <code>String</code>.
>        */
>       public static String join(Iterator iterator, String separator)
>       {
>           StringBuffer buf = new StringBuffer();
>           while (iterator.hasNext())
>           {
>               buf.append(iterator.next());
>               if (iterator.hasNext())
>               {
>                   buf.append(separator);
>               }
>           }
>           return buf.toString();
>       }
>
>       /**
>        * Takes a block of text which might have long lines in it and wraps
>        * the long lines based on the supplied wrapColumn parameter. It was
>        * initially implemented for use by VelocityEmail. If there are tabs
>        * in inString, you are going to get results that are a bit strange,
>        * since tabs are a single character but are displayed as 4 or 8
>        * spaces. Remove the tabs.
>        *
>        * @param inString   Text which is in need of word-wrapping.
>        * @param newline    The characters that define a newline.
>        * @param wrapColumn The column to wrap the words at.
>        * @return           The text with all the long lines word-wrapped.
>        */
>
>       public static String wrapText (String inString, String newline,
>                                      int wrapColumn)
>       {
>           StringTokenizer lineTokenizer = new StringTokenizer (
>                   inString, newline, true);
>           StringBuffer stringBuffer = new StringBuffer();
>
>           while (lineTokenizer.hasMoreTokens ())
>           {
>               try
>               {
>                   String nextLine = lineTokenizer.nextToken();
>
>                   if (nextLine.length() > wrapColumn)
>                   {
>                       // This line is long enough to be wrapped.
>                       nextLine = wrapLine (nextLine, newline, wrapColumn);
>                   }
>
>                   stringBuffer.append (nextLine);
>               }
>               catch (NoSuchElementException nsee)
>               {
>                   // thrown by nextToken(), but I don't know why it would
>                   break;
>               }
>           }
>
>           return (stringBuffer.toString());
>       }
>
>       /**
>        * Wraps a single line of text. Called by wrapText(). I can't
>        * think of any good reason for exposing this to the public,
>        * since wrapText should always be used AFAIK.
>        *
>        * @param line       A line which is in need of word-wrapping.
>        * @param newline    The characters that define a newline.
>        * @param wrapColumn The column to wrap the words at.
>        * @return           A line with newlines inserted.
>        */
>
>       protected static String wrapLine (String line, String newline,
>                                         int wrapColumn)
>       {
>           StringBuffer wrappedLine = new StringBuffer();
>
>           while (line.length() > wrapColumn)
>           {
>               int spaceToWrapAt = line.lastIndexOf (' ', wrapColumn);
>
>               if (spaceToWrapAt >= 0)
>               {
>                   wrappedLine.append (line.substring (0, spaceToWrapAt));
>                   wrappedLine.append (newline);
>                   line = line.substring (spaceToWrapAt + 1);
>               }
>
>               // This must be a really long word or URL. Pass it
>               // through unchanged even though it's longer than the
>               // wrapColumn would allow. This behavior could be
>               // dependent on a parameter for those situations when
>               // someone wants long words broken at line length.
>               else
>               {
>                   spaceToWrapAt = line.indexOf (' ', wrapColumn);
>
>                   if (spaceToWrapAt >= 0)
>                   {
>                       wrappedLine.append (line.substring (0, spaceToWrapAt));
>                       wrappedLine.append (newline);
>                       line = line.substring (spaceToWrapAt + 1);
>                   }
>                   else
>                   {
>                       wrappedLine.append (line);
>                       line = "";
>                   }
>               }
>           }
>
>           // Whatever is left in line is short enough to just pass through,
>           // just like a small small kidney stone
>           wrappedLine.append (line);
>
>           return (wrappedLine.toString());
>       }
>
>       /**
>        * Uncapitalise a string. That is, convert the first character into
>        * lower-case.
>        *
>        * @param str String to uncapitalise
>        *
>        * @return String uncapitalised
>        */
>       static public String uncapitalise(String str) {
>           return str.substring(0,1).toLowerCase() + str.substring(1);
>       }
>
>       /**
>        * Capitalise a string. That is, convert the first character into
>        * title-case.
>        *
>        * @param str String to capitalise
>        *
>        * @return String capitalised
>        */
>       static public String capitalise(String str) {
>           return "" + Character.toTitleCase(str.charAt(0)) + str.substring(1);
>       }
>
>       /**
>        * Replace a string with another string inside a larger string, once.
>        *
>        * @see #replace(String text, String repl, String with, int max)
>        */
>       public static String replaceOnce(String text, String repl, String with)
>       {
>           return replace(text, repl, with, 1);
>       }
>
>       /**
>        * @see #replace(String text, String repl, String with, int max)
>        */
>       public static String replace(String text, String repl, String with)
>       {
>           return replace(text, repl, with, -1);
>       }
>
>       /**
>        * @see #replace(String text, String repl, String with, int max)
>        */
>       public static String replace(String text, String repl, String with,
>                                    String max)
>       {
>           return replace(text, repl, with, Numbers.stringToInt(max, -1));
>       }
>
>       /**
>        * Replace a string with another string inside a larger string,
>        * for the first <code>max</code> values of the search string.  A
>        * <code>null</code> reference is passed to this method is a
>        * no-op.
>        *
>        * @param text Text to search and replace in.
>        * @param repl String to search for
>        * @param with String to replace with
>        * @param max Maximum number of values to replace, or
>        * <code>-1</code> if no maximum.
>        * @return The text with any replacements processed.
>        */
>       public static String replace(String text, String repl, String with,
>                                    int max)
>       {
>           if (text == null)
>           {
>               return null;
>           }
>
>           StringBuffer buf = new StringBuffer(text.length());
>           int start = 0, end = 0;
>           while ( (end = text.indexOf(repl, start)) != -1 )
>           {
>               //System.err.println("end=" + end);
>               buf.append(text.substring(start, end)).append(with);
>               start = end + repl.length();
>               //System.err.println("new start=" + start);
>
>               if (--max == 0)
>               {
>                   break;
>               }
>           }
>           buf.append(text.substring(start));
>           return buf.toString();
>       }
>
>       static public String overlayString(String text, String overlay, String start, String end) {
>           return overlayString(text,overlay,Numbers.stringToInt(start), Numbers.stringToInt(end));
>       }
>       /**
>        * Overlay a part of a string with another string.
>        *
>        * @param text String to do overlaying in
>        * @param overlay String to overlay
>        * @param start int to start overlaying at
>        * @param end   int to stop overlaying before
>        *
>        * @return String with overlayed text
>        */
>       static public String overlayString(String text, String overlay, int start, int end) {
>           String pre = text.substring(0, start);
>           String post = text.substring(end);
>           return pre+overlay+post;
>       }
>
>       static public String repeat(String str, String n) {
>           return repeat(str, Numbers.stringToInt(n,1));
>       }
>
>       /**
>        * Repeat a string n times to form a new string.
>        *
>        * @param str String to repeat
>        * @param n   int    number of times to repeat
>        *
>        * @return String with repeated string
>        */
>       static public String repeat(String str, int n) {
>           StringBuffer buffer = new StringBuffer(n*str.length());
>           for(int i=0; i<n; i++) {
>               buffer.append(str);
>           }
>           return buffer.toString();
>       }
>
>   // these are not really of use in the Java world. Only if you're a C afficionado
>   //    static public String sprintf(String format, Object[] list);
>   //    static public Object[] sscanf(String str, String format);
>   //    static public String pack(String[] strs, String format);
>   //    static public String[] unpack(String str, String format);
>
>
>       /**
>        * Center a string in a larger string of size n.
>        * Uses spaces as the value to buffer the string with..
>        *
>        * @param str String to center
>        * @param n   int    size of new String
>        *
>        * @return String containing centered String
>        */
>       static public String center(String str, int n) {
>           return center(str, n, " ");
>       }
>
>       static public String center(String str, String n, String delim) {
>           return center(str,Numbers.stringToInt(n), delim);
>       }
>
>       /**
>        * Center a string in a larger string of size n.
>        * Uses a supplied String as the value to buffer the string with..
>        *
>        * @param str String to center
>        * @param n   int    size of new String
>        * @param delim String to buffer the new String with
>        *
>        * @return String containing centered String
>        */
>       static public String center(String str, int n, String delim) {
>           int sz = str.length();
>           int p = n-sz;
>           if(p < 1) {
>               return str;
>           }
>           str = leftPad(str,sz+p/2, delim);
>           str = rightPad(str, n, delim);
>           return str;
>       }
>
>       /**
>        * Remove the last newline, and everything after it from a String.
>        *
>        * @param str String to chomp the newline from
>        *
>        * @return String without chomped newline
>        */
>       static public String chomp(String str) {
>           return chomp(str, "\n");
>       }
>
>       /**
>        * Remove the last value of a supplied String, and everything after it
>        * from a String.
>        *
>        * @param str String to chomp from
>        * @param sep String to chomp
>        *
>        * @return String without chomped ending
>        */
>       static public String chomp(String str, String sep) {
>           int idx = str.lastIndexOf(sep);
>           if(idx != -1) {
>               return str.substring(0,idx);
>           } else {
>               return str;
>           }
>       }
>
>       /**
>        * Remove a newline if and only if it is at the end
>        * of the supplied string.
>        */
>       static public String chompLast(String str) {
>           return chompLast(str, "\n");
>       }
>       static public String chompLast(String str, String sep) {
>           if(str.length() == 0) {
>               return str;
>           }
>           String sub = str.substring(str.length() - sep.length());
>           if(sep.equals(sub)) {
>               return str.substring(0,str.length()-sep.length());
>           } else {
>               return str;
>           }
>       }
>
>       /**
>        * Remove everything and return the last value of a supplied String, and
>        * everything after it from a String.
>        *
>        * @param str String to chomp from
>        * @param sep String to chomp
>        *
>        * @return String chomped
>        */
>       static public String getChomp(String str, String sep) {
>           int idx = str.lastIndexOf(sep);
>           if(idx == str.length()-sep.length()) {
>               return sep;
>           } else
>           if(idx != -1) {
>               return str.substring(idx);
>           } else {
>               return "";
>           }
>       }
>
>       /**
>        * Remove the first value of a supplied String, and everything before it
>        * from a String.
>        *
>        * @param str String to chomp from
>        * @param sep String to chomp
>        *
>        * @return String without chomped beginning
>        */
>       static public String prechomp(String str, String sep) {
>           int idx = str.indexOf(sep);
>           if(idx != -1) {
>               return str.substring(idx+sep.length());
>           } else {
>               return str;
>           }
>       }
>
>       /**
>        * Remove and return everything before the first value of a
>        * supplied String from another String.
>        *
>        * @param str String to chomp from
>        * @param sep String to chomp
>        *
>        * @return String prechomped
>        */
>       static public String getPrechomp(String str, String sep) {
>           int idx = str.indexOf(sep);
>           if(idx != -1) {
>               return str.substring(0,idx+sep.length());
>           } else {
>               return "";
>           }
>       }
>
>       /**
>        * Remove the last character from a String. If the String
>        * ends in \r\n, then remove both of them.
>        *
>        * @param str String to chop last character from
>        *
>        * @return String without last character
>        */
>       static public String chop(String str) {
>           if("".equals(str)) {
>               return "";
>           }
>           if(str.length() == 1) {
>               return "";
>           }
>           int lastIdx = str.length()-1;
>           String ret = str.substring(0,lastIdx);
>           char last = str.charAt(lastIdx);
>           if(last == '\n') {
>               if(ret.charAt(lastIdx-1) == '\r') {
>                   return ret.substring(0,lastIdx-1);
>               }
>           }
>           return ret;
>       }
>
>       /**
>        * Remove \n from end of a String if it's there.
>        * If a \r precedes it, then remove that too.
>        *
>        * @param str String to chop a newline from
>        *
>        * @param String without newline on end
>        */
>       static public String chopNewline(String str) {
>           int lastIdx = str.length()-1;
>           char last = str.charAt(lastIdx);
>           if(last == '\n') {
>               if(str.charAt(lastIdx-1) == '\r') {
>                   lastIdx --;
>               }
>           } else {
>               lastIdx++;
>           }
>           return str.substring(0,lastIdx);
>       }
>
>       /**
>        * Creates a CharSet object which allows a certain amount of
>        * set logic to be performed upon the following syntax:
>        *
>        * "aeio" which implies 'a','e',..
>        * "^e" implies not e. However it only negates, it's not
>        * a set in itself due to the size of that set in unicode.
>        * "ej-m" implies e,j->m. e,j,k,l,m.
>        */
>       static public CharSet evaluateSet(String[] set) {
>           return new CharSet(set);
>       }
>
>       static public int count(String str, String set) {
>           String[] strs = new String[1];
>           strs[0] = set;
>           return count(str, strs);
>       }
>       /**
>        * Takes an argument in set-syntax, see evaluateSet,
>        * and returns the number of characters present in the specified string.
>        * An example would be:   count("hello", {"c-f","o"}) returns 2.
>        *
>        * @param str String target to count characters in
>        * @param str String[] set of characters to count
>        */
>       static public int count(String str, String[] set) {
>           CharSet chars = evaluateSet(set);
>           int count = 0;
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length;
>           for(int i=0; i<sz; i++) {
>               if(chars.contains(chrs[i])) {
>                   count++;
>               }
>           }
>           return count;
>       }
>
>       static public String delete(String str, String set) {
>           String[] strs = new String[1];
>           strs[0] = set;
>           return delete(str, strs);
>       }
>       /**
>        * Takes an argument in set-syntax, see evaluateSet,
>        * and deletes any of characters present in the specified string.
>        * An example would be:   delete("hello", {"c-f","o"}) returns "hll"
>        *
>        * @param str String target to delete characters from
>        * @param str String[] set of characters to delete
>        */
>       static public String delete(String str, String[] set) {
>           CharSet chars = evaluateSet(set);
>           StringBuffer buffer = new StringBuffer(str.length());
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length;
>           for(int i=0; i<sz; i++) {
>               if(!chars.contains(chrs[i])) {
>                   buffer.append(chrs[i]);
>               }
>           }
>           return buffer.toString();
>       }
>
>       static public String squeeze(String str, String set) {
>           String[] strs = new String[1];
>           strs[0] = set;
>           return squeeze(str, strs);
>       }
>       /**
>        * Squeezes any repititions of a character that is mentioned in the
>        * supplied set. An example is:
>        *    squeeze("hello", {"el"})  => "helo"
>        * See evaluateSet for set-syntax.
>        */
>       static public String squeeze(String str, String[] set) {
>           CharSet chars = evaluateSet(set);
>           StringBuffer buffer = new StringBuffer(str.length());
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length;
>           char lastChar = ' ';
>           char ch = ' ';
>           for(int i=0; i<sz; i++) {
>               ch = chrs[i];
>               if(chars.contains(ch)) {
>                   if( (ch == lastChar) && (i != 0) ) {
>                       continue;
>                   }
>               }
>               buffer.append(ch);
>               lastChar = ch;
>           }
>           return buffer.toString();
>       }
>
>       /**
>        * Translate characters in a String.
>        * An example is:  translate("hello", "ho", "jy") => jelly
>        * If the length of characters to search for is greater than the
>        * length of characters to replace, then the last character is
>        * used.
>        *
>        * @param target String to replace characters  in
>        * @param repl String to find that will be replaced
>        * @param with String to put into the target String
>        */
>       static public String translate(String target, String repl, String with) {
>           StringBuffer buffer = new StringBuffer(target.length());
>           char[] chrs = target.toCharArray();
>           char[] withChrs = with.toCharArray();
>           int sz = chrs.length;
>           int withMax = with.length() - 1;
>           for(int i=0; i<sz; i++) {
>               int idx = repl.indexOf(chrs[i]);
>               if(idx != -1) {
>                   if(idx > withMax) {
>                       idx = withMax;
>                   }
>                   buffer.append(withChrs[idx]);
>               } else {
>                   buffer.append(chrs[i]);
>               }
>           }
>           return buffer.toString();
>       }
>
>       // spec 3.10.6
>       /**
>        * Escapes any values it finds into their String form.
>        * So a tab becomes the characters '\\' and 't'.
>        *
>        * @param str String to escape values in
>        *
>        * @return String with escaped values
>        */
>       // improved with code from  cybertiger@cyberiantiger.org
>       // unicode from him, and defaul for < 32's.
>       static public String escape(String str) {
>           int sz = str.length();
>           StringBuffer buffer = new StringBuffer(2*sz);
>           for(int i=0; i<sz; i++) {
>               char ch = str.charAt(i);
>
>               // handle unicode
>               if(ch > 0xfff) {
>                   buffer.append("\\u"+Integer.toHexString(ch));
>               } else
>               if(ch > 0xff) {
>                   buffer.append("\\u0"+Integer.toHexString(ch));
>               } else
>               if(ch > 0x7f) {
>                   buffer.append("\\u00"+Integer.toHexString(ch));
>               } else
>               if(ch < 32) {
>                   switch(ch) {
>                       case '\b' :
>                           buffer.append('\\');
>                           buffer.append('b');
>                           break;
>                       case '\n' :
>                           buffer.append('\\');
>                           buffer.append('n');
>                           break;
>                       case '\t' :
>                           buffer.append('\\');
>                           buffer.append('t');
>                           break;
>                       case '\f' :
>                           buffer.append('\\');
>                           buffer.append('f');
>                           break;
>                       case '\r' :
>                           buffer.append('\\');
>                           buffer.append('r');
>                           break;
>                       default :
>                           if( ch > 0xf ) {
>                               buffer.append("\\u00"+Integer.toHexString(ch));
>                           } else {
>                               buffer.append("\\u000"+Integer.toHexString(ch));
>                           }
>                           break;
>                   }
>               } else {
>                   switch(ch) {
>                       case '\'' :
>                           buffer.append('\\');
>                           buffer.append('\'');
>                           break;
>                       case '"' :
>                           buffer.append('\\');
>                           buffer.append('"');
>                           break;
>                       case '\\' :
>                           buffer.append('\\');
>                           buffer.append('\\');
>                           break;
>                       default :
>                           buffer.append(ch);
>                           break;
>                   }
>               }
>           }
>           return buffer.toString();
>       }
>
>       /**
>        * Right pad a String with spaces. Pad to a size of n.
>        */
>       static public String rightPad(String str, int n) {
>           return rightPad(str, n, " ");
>       }
>       static public String rightPad(String str, String n, String delim) {
>           return rightPad(str, Numbers.stringToInt(n), delim);
>       }
>       /**
>        * Right pad a String with a specified string. Pad to a size of n.
>        *
>        * @param str   String to pad out
>        * @param n     int    size to pad to
>        * @param delim String to pad with
>        */
>       static public String rightPad(String str, int n, String delim) {
>           n = (n - str.length())/delim.length();
>           if(n > 0) {
>               str += repeat(delim,n);
>           }
>           return str;
>       }
>
>       /**
>        * Left pad a String with spaces. Pad to a size of n.
>        */
>       static public String leftPad(String str, int n) {
>           return leftPad(str, n, " ");
>       }
>       static public String leftPad(String str, String n, String delim) {
>           return leftPad(str, Numbers.stringToInt(n), delim);
>       }
>       /**
>        * Left pad a String with a specified string. Pad to a size of n.
>        *
>        * @param str   String to pad out
>        * @param n     int    size to pad to
>        * @param delim String to pad with
>        */
>       static public String leftPad(String str, int n, String delim) {
>           n = (n - str.length())/delim.length();
>           if(n > 0) {
>               str = repeat(delim,n) + str;
>           }
>           return str;
>       }
>
>       // faster algorithm available. unsure if usable in Java
>       /**
>        * Reverse a String.
>        */
>       static public String reverse(String str) {
>           /*
>           int sz = str.length();
>           StringBuffer buffer = new StringBuffer(sz);
>           for(int i=sz; i>0; i--) {
>               buffer.append(str.charAt(i-1));
>           }
>           return buffer.toString();
>           */
>           return new StringBuffer(str).reverse().toString();
>       }
>
>       /**
>        * Remove whitespace from the front and back of a String.
>        */
>       static public String strip(String str) {
>           return strip(str, null);
>       }
>       /**
>        * Remove a specified String from the front and back of a
>        * String. If Whitespace is wanted to be removed, used the
>        * strip(String) method.
>        */
>       static public String strip(String str, String delim) {
>           str = stripStart(str, delim);
>           return stripEnd(str, delim);
>       }
>
>       /**
>        * Swaps the case of String. Properly looks after
>        * making sure the start of words are Titlecase and not
>        * Uppercase.
>        */
>       static public String swapCase(String str) {
>           int sz = str.length();
>           StringBuffer buffer = new StringBuffer(sz);
>
>           boolean whitespace = false;
>           char ch = 0;
>           char tmp = 0;
>
>           for(int i=0; i<sz; i++) {
>               ch = str.charAt(i);
>               if(Character.isUpperCase(ch)) {
>                   tmp = Character.toLowerCase(ch);
>               } else
>               if(Character.isTitleCase(ch)) {
>                   tmp = Character.toLowerCase(ch);
>               } else
>               if(Character.isLowerCase(ch)) {
>                   if(whitespace) {
>                       tmp = Character.toTitleCase(ch);
>                   } else {
>                       tmp = Character.toUpperCase(ch);
>                   }
>               }
>               buffer.append(tmp);
>               whitespace = Character.isWhitespace(ch);
>           }
>           return buffer.toString();
>       }
>
>
>       // From .NET
>       /**
>        * Find the earlier index of any of a set of potential substrings.
>        */
>       static public int indexOfAny(String str, String[] strs) {
>           int sz = strs.length;
>
>           // String's can't have a MAX_VALUEth index.
>           int ret = Integer.MAX_VALUE;
>
>           int tmp = 0;
>           for(int i=0; i<sz; i++) {
>               tmp = str.indexOf(strs[i]);
>               if(tmp == -1) {
>                   continue;
>               }
>
>               if(tmp < ret) {
>                   ret = tmp;
>               }
>           }
>
>           return (ret == Integer.MAX_VALUE)?-1:ret;
>       }
>
>       /**
>        * Find the latest index of any of a set of potential substrings.
>        */
>       static public int lastIndexOfAny(String str, String[] strs) {
>           int sz = strs.length;
>           int ret = -1;
>           int tmp = 0;
>           for(int i=0; i<sz; i++) {
>               tmp = str.lastIndexOf(strs[i]);
>               if(tmp > ret) {
>                   ret = tmp;
>               }
>           }
>           return ret;
>       }
>
>       /**
>        * Strip any of a supplied substring from the end of a String..
>        */
>       static public String stripEnd(String str, String ch) {
>           int end = str.length();
>
>           if(ch == null) {
>               while( Character.isWhitespace( str.charAt(end-1) ) ) {
>                   end--;
>               }
>           } else {
>               char chr = ch.charAt(0);
>               while( str.charAt(end-1) == chr ) {
>                   end--;
>               }
>           }
>           return str.substring(0, end);
>       }
>
>       /**
>        * Strip any of a supplied substring from the start of a String..
>        */
>       static public String stripStart(String str, String ch) {
>           int start = 0;
>
>           if(ch == null) {
>               while( Character.isWhitespace( str.charAt(start) ) ) {
>                   start++;
>               }
>           } else {
>               char chr = ch.charAt(0);
>               while( str.charAt(start) == chr ) {
>                   start++;
>               }
>           }
>           return str.substring(start);
>       }
>
>       /**
>        * Find the Levenshtein distance between two strings.
>        * This is the number of changes needed to change one string into
>        * another. Where each change is a single character modification.
>        *
>        * This implemmentation of the levenshtein distance algorithm
>        * is from http://www.merriampark.com/ld.htm
>        */
>       static public int getLevenshteinDistance(String s, String t) {
>           int d[][]; // matrix
>           int n; // length of s
>           int m; // length of t
>           int i; // iterates through s
>           int j; // iterates through t
>           char s_i; // ith character of s
>           char t_j; // jth character of t
>           int cost; // cost
>
>           // Step 1
>           n = s.length ();
>           m = t.length ();
>           if (n == 0) {
>               return m;
>           }
>           if (m == 0) {
>               return n;
>           }
>           d = new int[n+1][m+1];
>
>           // Step 2
>           for (i = 0; i <= n; i++) {
>               d[i][0] = i;
>           }
>
>           for (j = 0; j <= m; j++) {
>               d[0][j] = j;
>           }
>
>           // Step 3
>           for (i = 1; i <= n; i++) {
>               s_i = s.charAt (i - 1);
>
>               // Step 4
>               for (j = 1; j <= m; j++) {
>                   t_j = t.charAt (j - 1);
>
>                   // Step 5
>                   if (s_i == t_j) {
>                       cost = 0;
>                   } else {
>                       cost = 1;
>                   }
>
>                   // Step 6
>                   d[i][j] = Numbers.minimum(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1] + cost);
>               }
>           }
>
>           // Step 7
>           return d[n][m];
>       }
>
>       /**
>        * Quote a string so that it may be used in a regular expression
>        * without any parts of the string being considered as a
>        * part of the regular expression's control characters.
>        */
>       static public String quoteRegularExpression(String str) {
>           // replace ? + * / . ^ $ as long as they're not in character
>           // class. so must be done by hand
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length;
>           StringBuffer buffer = new StringBuffer(2*sz);
>           for(int i=0; i<sz; i++) {
>               switch(chrs[i]) {
>                 case '[' :
>                 case ']' :
>                 case '?' :
>                 case '+' :
>                 case '*' :
>                 case '/' :
>                 case '.' :
>                 case '^' :
>                 case '$' :
>                   buffer.append("\\");
>                 default :
>                   buffer.append(chrs[i]);
>               }
>           }
>           return buffer.toString();
>       }
>
>       /**
>        * Capitalise all the words in a string. Uses Character.isWhitespace
>        * as a separator between words.
>        */
>       static public String capitaliseAllWords(String str) {
>           int sz = str.length();
>           StringBuffer buffer = new StringBuffer(sz);
>           boolean space = true;
>           for(int i=0; i<sz; i++) {
>               char ch = str.charAt(i);
>               if(Character.isWhitespace(ch)) {
>                   buffer.append(ch);
>                   space = true;
>               } else
>               if(space) {
>                   buffer.append(Character.toTitleCase(ch));
>                   space = false;
>               } else {
>                   buffer.append(ch);
>               }
>           }
>           return buffer.toString();
>       }
>
>       /**
>        * Create a word-wrapped version of a String. Wrap at 80 characters and
>        * use newlines as the delimiter. If a word is over 80 characters long
>        * use a - sign to split it.
>        */
>       static public String wordWrap(String str) {
>           return wordWrap(str, 80, "\n", "-");
>       }
>       /**
>        * Create a word-wrapped version of a String. Wrap at a specified width and
>        * use newlines as the delimiter. If a word is over the width in lenght
>        * use a - sign to split it.
>        */
>       static public String wordWrap(String str, int width) {
>           return wordWrap(str, width, "\n", "-");
>       }
>       static public String wordWrap(String str, String width, String delim, String split) {
>           return wordWrap(str, Numbers.stringToInt(width), delim, split);
>       }
>       /**
>        * Word-wrap a string.
>        *
>        * @param str   String to word-wrap
>        * @param width int to wrap at
>        * @param delim String to use to separate lines
>        * @param split String to use to split a word greater than width long
>        *
>        * @return String that has been word wrapped
>        */
>       static public String wordWrap(String str, int width, String delim, String split) {
>           int sz = str.length();
>
>           /// shift width up one. mainly as it makes the logic easier
>           width++;
>
>           // our best guess as to an initial size
>           StringBuffer buffer = new StringBuffer(sz/width*delim.length()+sz);
>
>           // every line will include a delim on the end
>           width = width - delim.length();
>
>           int idx = -1;
>           String substr = null;
>
>           // beware: i is rolled-back inside the loop
>           for(int i=0; i<sz; i+=width) {
>
>               // on the last line
>               if(i > sz - width) {
>                   buffer.append(str.substring(i));
>   //                System.err.print("LAST-LINE: "+str.substring(i));
>                   break;
>               }
>
>   //            System.err.println("loop[i] is: "+i);
>               // the current line
>               substr = str.substring(i, i+width);
>
>               // is the delim already on the line
>               idx = substr.indexOf(delim);
>               if(idx != -1) {
>                   buffer.append(substr.substring(0,idx));
>   //                System.err.println("Substr: '"+substr.substring(0,idx)+"'");
>                   buffer.append(delim);
>                   i -= width-idx-delim.length();
>
>   //                System.err.println("loop[i] is now: "+i);
>   //                System.err.println("found-whitespace: '"+substr.charAt(idx+1)+"'.");
>                   // Erase a space after a delim. Is this too obscure?
>                   if(substr.charAt(idx+1) != '\n') {
>                       if(Character.isWhitespace(substr.charAt(idx+1))) {
>                           i++;
>                       }
>                   }
>   //                System.err.println("i -= "+width+"-"+idx);
>                   continue;
>               }
>
>               idx = -1;
>
>               // figure out where the last space is
>               char[] chrs = substr.toCharArray();
>               for(int j=width; j>0; j--) {
>                   if(Character.isWhitespace(chrs[j-1])) {
>                       idx = j;
>   //                    System.err.println("Found whitespace: "+idx);
>                       break;
>                   }
>               }
>
>               // idx is the last whitespace on the line.
>   //            System.err.println("idx is "+idx);
>               if(idx == -1) {
>                   for(int j=width; j>0; j--) {
>                       if(chrs[j-1] == '-') {
>                           idx = j;
>   //                        System.err.println("Found Dash: "+idx);
>                           break;
>                       }
>                   }
>                   if(idx == -1) {
>                       buffer.append(substr);
>                       buffer.append(delim);
>   //                    System.err.print(substr);
>   //                    System.err.print(delim);
>                   } else {
>                       if(idx != width) {
>                           idx++;
>                       }
>                       buffer.append(substr.substring(0,idx));
>                       buffer.append(delim);
>   //                    System.err.print(substr.substring(0,idx));
>   //                    System.err.print(delim);
>                       i -= width-idx;
>                   }
>               } else {
>                   /*
>                   if(force) {
>                       if(idx == width-1) {
>                           buffer.append(substr);
>                           buffer.append(delim);
>                       } else {
>                           // stick a split in.
>                           int splitsz = split.length();
>                           buffer.append(substr.substring(0,width-splitsz));
>                           buffer.append(split);
>                           buffer.append(delim);
>                           i -= splitsz;
>                       }
>                   } else {
>                   */
>                       // insert spaces
>                       buffer.append(substr.substring(0,idx));
>                       buffer.append(repeat(" ",width-idx));
>   //                    System.err.print(substr.substring(0,idx));
>   //                    System.err.print(repeat(" ",width-idx));
>                       buffer.append(delim);
>   //                    System.err.print(delim);
>   //                    System.err.println("i -= "+width+"-"+idx);
>                       i -= width-idx;
>   //                }
>               }
>           }
>   //        System.err.println("\n*************");
>           return buffer.toString();
>       }
>
>
>       /**
>        * Get the String that is nested in between two instances of the
>        * same String.
>        *
>        * @param str   String containing nested-string
>        * @param tag  String before and after nested-string
>        *
>        * @return String that was nested
>        */
>       static public String getNestedString(String str, String tag) {
>           return getNestedString(str, tag, tag);
>       }
>       /**
>        * Get the string that is nested in between two strings.
>        *
>        * @param str   String containing nested-string
>        * @param open  String before nested-string
>        * @param close String after nested-string
>        *
>        * @return String that was nested
>        */
>       static public String getNestedString(String str, String open, String close) {
>           int start = str.indexOf(open);
>           if(start != -1) {
>               int end = str.indexOf(close, start+open.length());
>               if(end != -1) {
>                   return str.substring(start+open.length(), end);
>               }
>           }
>           return "";
>       }
>
>
>       /**
>        * How mmany times is the substring in the larger string.
>        */
>       static public int countMatches(String str, String sub) {
>           int count = 0;
>           int idx = 0;
>           while( (idx = str.indexOf(sub, idx)) != -1) {
>               count++;
>               idx += sub.length();
>           }
>           return count;
>       }
>
>       /**
>        * Is a String a word. Contains only unicode letters.
>        */
>       static public boolean isWord(String str) {
>           int sz = str.length();
>           for(int i=0; i<sz; i++) {
>               if(!Character.isLetter(str.charAt(i))) {
>                   return false;
>               }
>           }
>           return true;
>       }
>
>       /**
>        * Does a String contain only unicode letters or digits.
>        */
>       static public boolean isAlphanumeric(String str) {
>           int sz = str.length();
>           for(int i=0; i<sz; i++) {
>               if(!Character.isLetterOrDigit(str.charAt(i))) {
>                   return false;
>               }
>           }
>           return true;
>       }
>
>       /**
>        * Does a String contain only unicode digits.
>        */
>       static public boolean isNumeric(String str) {
>           int sz = str.length();
>           for(int i=0; i<sz; i++) {
>               if(!Character.isDigit(str.charAt(i))) {
>                   return false;
>               }
>           }
>           return true;
>       }
>
>       /**
>        * Is a String a line, containing only letters, digits or
>        * whitespace, and ending with an optional newline.
>        * NB: Punctuation not allowed.
>        */
>       static public boolean isLine(String str) {
>           char ch = 0;
>           char[] chrs = str.toCharArray();
>           int sz = chrs.length-1;
>           for(int i=0; i<sz-2; i++) {
>               if(!Character.isLetterOrDigit(chrs[i])) {
>                   if(!Character.isWhitespace(chrs[i])) {
>                       return false;
>                   }
>               }
>           }
>           if(!Character.isLetterOrDigit(chrs[sz-1])) {
>               if(!Character.isWhitespace(chrs[sz-1])) {
>                   if(chrs[sz-1] != '\r') {
>                       return false;
>                   } else
>                   if(chrs[sz] != '\n') {
>                       return false;
>                   }
>               }
>           }
>           if(!Character.isLetterOrDigit(chrs[sz])) {
>               if(!Character.isWhitespace(chrs[sz])) {
>                   if(chrs[sz] != '\n') {
>                       return false;
>                   }
>               }
>           }
>           return true;
>       }
>
>       /*
>       // needs to handle punctuation
>       static public boolean isText(String str) {
>           int sz = str.length();
>           char ch = 0;
>           for(int i=0; i<sz; i++) {
>               ch = str.charAt(i);
>               if(!Character.isLetterOrDigit(ch)) {
>                   if(!Character.isWhitespace(ch)) {
>                       if( (ch != '\n') && (ch != '\r') ) {
>                           return false;
>                       }
>                   }
>               }
>           }
>           return true;
>       }
>       */
>
>       /**
>        * Return either the passed in String, or if it is null,
>        * then an empty String.
>        */
>       static public String defaultString(String str) {
>           return defaultString(str,"");
>       }
>
>       /**
>        * Return either the passed in String, or if it is null,
>        * then a passed in default String.
>        */
>       static public String defaultString(String str, String def) {
>           return (str == null)?def:str;
>       }
>
>       static public String upperCase(String str) {
>           return str.toUpperCase();
>       }
>
>       static public String lowerCase(String str) {
>           return str.toLowerCase();
>       }
>
>       static public String substring(String str, String start) {
>           return substring(str, Numbers.stringToInt(start));
>       }
>       static public String substring(String str, int start) {
>           if(str == null) {
>               return null;
>           }
>
>           // handle negatives
>           if(start < 0) {
>               start = str.length() + start;    // remember start is negative
>           }
>
>           if(start < 0) {
>               start = 0;
>           }
>
>           return str.substring(start);
>       }
>       static public String substring(String str, String start, String end) {
>           return substring(str, Numbers.stringToInt(start), Numbers.stringToInt(end));
>       }
>       static public String substring(String str, int start, int end) {
>           if(str == null) {
>               return null;
>           }
>
>           // handle negatives
>           if(end < 0) {
>               end = str.length() + end;    // remember end is negative
>           }
>           if(start < 0) {
>               start = str.length() + start;    // remember start is negative
>           }
>
>           // check length next
>           if(end > str.length()) {
>               // check this works.
>               end = str.length();
>           }
>
>           // what if start is greater than end??
>
>           if(start < 0) {
>               start = 0;
>           }
>
>           // a good default?
>           if(end < 0) {
>               end = 0;
>           }
>
>           return str.substring(start, end);
>       }
>
>
>       static public String random(int count) {
>           return random(count, false, false);
>       }
>
>       static public String randomAscii(int count) {
>           return random(count, 32, 127, false, false);
>       }
>       static public String randomAlphabetic(int count) {
>           return random(count, true, false);
>       }
>       static public String randomAlphanumeric(int count) {
>           return random(count, true, true);
>       }
>       static public String randomNumeric(int count) {
>           return random(count, false, true);
>       }
>
>       static public String random(int count, boolean letters, boolean numbers) {
>           return random(count, 0, 0, letters, numbers);
>       }
>       static public String random(int count, int start, int end, boolean letters, boolean numbers) {
>           return random(count, start, end, letters, numbers, null);
>       }
>       /**
>        * Create a random string based on a variety of options.
>        *
>        * @param count int length of random string to create
>        * @param start int position in set of chars to start at
>        * @param end int position in set of chars to end before
>        * @param letters boolean only allow letters?
>        * @param numbers boolean only allow numbers?
>        * @param set char[] set of chars to choose randoms from.
>        *        If null, then it will use the set of all chars.
>        *
>        */
>       static public String random(int count, int start, int end, boolean letters, boolean numbers, char[] set) {
>           if( (start == 0) && (end == 0) ) {
>               end = (int)'z';
>               start = (int)' ';
>               if(!letters && !numbers) {
>                   start = 0;
>                   end = Integer.MAX_VALUE;
>               }
>           }
>           Random rnd = new Random();
>           StringBuffer buffer = new StringBuffer();
>           int gap = end - start;
>
>           while(count-- != 0) {
>               char ch;
>               if(set == null) {
>                   ch = (char)(rnd.nextInt(gap) + start);
>               } else {
>                   ch = set[rnd.nextInt(gap) + start];
>               }
>               if( (letters && numbers && Character.isLetterOrDigit(ch)) ||
>                   (letters && Character.isLetter(ch)) ||
>                   (numbers && Character.isDigit(ch)) ||
>                   (!letters && !numbers)
>                 )
>               {
>                   buffer.append( ch );
>               } else {
>                   count++;
>               }
>           }
>           return buffer.toString();
>       }
>
>       static public String random(int count, String set) {
>           return random(count, set.toCharArray());
>       }
>
>       static public String random(int count, char[] set) {
>           return random(count,0,set.length-1,false,false,set);
>       }
>
>       static public String reverseDottedName(String text) {
>           return reverseDelimitedString(text, ".");
>       }
>
>       static public String reverseDelimitedString(String text, String delimiter) {
>           // could implement manually, but simple way is to reuse other,
>           // probably slower, methods.
>           String[] strs = split(text, delimiter);
>   //        CollectionsUtils.reverseArray(strs);
>   // call private method instead for the moment.
>           reverseArray(strs);
>           return join(strs, delimiter);
>       }
>
>   /// TAKEN FROM CollectionsUtils. Need to find a solution.
>       static private void reverseArray(Object[] array) {
>           int i = 0;
>           int j = array.length - 1;
>           Object tmp;
>
>           while(j>i) {
>               tmp = array[j];
>               array[j] = array[i];
>               array[i] = tmp;
>               j--;
>               i++;
>           }
>       }
>
>
>       /**
>        * Interpolate variables into a String.
>        */
>       static public String interpolate(String text, Map map) {
>           Iterator keys = map.keySet().iterator();
>           while(keys.hasNext()) {
>               String key = keys.next().toString();
>               String value = map.get(key).toString();
>               text = replace(text, "${"+key+"}", value);
>               if(key.indexOf(" ") == -1) {
>                   text = replace(text, "$"+key, value);
>               }
>           }
>           return text;
>       }
>
>       /**
>        * Convert a string from unicode to bytes in a native encoding.
>        * The string must be in unicode (as Java always expects this);
>        * {@link #convertNativeToUnicode(String, String)} will convert
>        * strings in native encodings into unicode.  This method is
>        * generally used to create a <code>String</code> for use as
>        * output, and is useful when dealing with I18N.
>        *
>        * @param source String the unicode string to convert
>        * @param charset String the name of the charset into which to
>        * convert.
>        * @return The string given represented in the native encoding
>        * specified.
>        * @see #convertNativeToUnicode(String, String)
>        */
>       public static String convertUnicodeToNative(String source, String charset)
>           throws IOException
>       {
>           ByteArrayOutputStream baos = new ByteArrayOutputStream();
>           OutputStreamWriter out = new OutputStreamWriter(baos, charset);
>           out.write(source);
>           out.close();
>           return baos.toString();
>       }
>
>       /**
>        * Convert a string from a native encoding to unicode.  This
>        * method is generally used to create a <code>String</code> for
>        * use as input, and is useful when dealing with I18N.
>        *
>        * @param input String the input to convert from native encoding
>        * to unicode.
>        * @param charset String the charset from which to convert.
>        * @return The string given represented in unicode rather than the
>        * specified native encoding.
>        */
>       public static String convertNativeToUnicode(String input, String charset)
>           throws IOException
>       {
>           InputStreamReader in = new InputStreamReader
>               (new ByteArrayInputStream(input.getBytes()), charset);
>           StringBuffer output = new StringBuffer();
>           char[] buf = new char[CHAR_BUFFER_SIZE];
>           int count = 0;
>           while ((count = in.read(buf, 0, CHAR_BUFFER_SIZE)) > 0)
>           {
>               output.append(buf, 0, count);
>           }
>           in.close();
>           return output.toString();
>       }
>   }
>
>
>   /**
>    * A range of characters. Able to understand the idea of a contiguous
>    * sublist of an alphbet, a negated concept, and a set of characters.
>    * Used by StringUtil to handle sets of characters.
>    *
>    * @author bayard@generationjava.com
>    * @version 0.4 20010812
>    */
>   class CharRange {
>
>       /**
>        * Used internally to represent null in a char.
>        */
>       static private char UNSET;
>
>       private char start;
>       private char close;
>       private boolean negated;
>
>       /**
>        * Construct a CharRange over a single character.
>        *
>        * @param start char over which this range is placed
>        */
>       public CharRange(char start) {
>           this.start = start;
>       }
>
>       /**
>        * Construct a CharRange over a set of characters.
>        *
>        * @param start char start character in this range. inclusive
>        * @param close char close character in this range. inclusive
>        */
>       public CharRange(char start, char close) {
>           this.start = start;
>           this.close = close;
>       }
>
>       /**
>        * Construct a CharRange over a set of characters.
>        *
>        * @param start String start first character is in this range (inclusive).
>        * @param close String first character is close character in this
>        * range (inclusive).
>        */
>       public CharRange(String start, String close) {
>           this.start = start.charAt(0);
>           this.close = close.charAt(0);
>       }
>
>       public char getStart() {
>           return this.start;
>       }
>
>       public char getEnd() {
>           return this.close;
>       }
>
>       public void setStart(char ch) {
>           this.start = ch;
>       }
>
>       public void setEnd(char ch) {
>           this.close = ch;
>       }
>
>       /**
>        * Is this CharRange over many characters
>        *
>        * @return boolean true is many characters
>        */
>       public boolean isRange() {
>           return this.close != UNSET;
>       }
>
>       /**
>        * Is the passed in character inside this range
>        *
>        * @return boolean true is in range
>        */
>       public boolean inRange(char ch) {
>           if(isRange()) {
>               return ((ch >= start) && (ch <= close) );
>           } else {
>               return start == ch;
>           }
>       }
>
>       /**
>        * Is this CharRange negated
>        *
>        * @return boolean true is negated
>        */
>       public boolean isNegated() {
>           return negated;
>       }
>
>       /**
>        * Make this character range be negated.
>        * This implies that this CharRange is over all characters except
>        * the ones in this range.
>        */
>       public void setNegated(boolean b) {
>           this.negated = b;
>       }
>
>       public String toString() {
>           String str = "";
>           if(isNegated()) {
>               str += "^";
>           }
>           str += start;
>           if(isRange()) {
>               str += "-";
>               str += close;
>           }
>           return str;
>       }
>   }
>
>
>
>   /**
>    * A set of characters. You can iterate over the characters in the
>    * set.
>    *
>    * @author bayard@generationjava.com
>    * @version 0.4 20010812
>    */
>   class CharSet {
>
>       // used to be a com.generationjava.collections.typed.TypedList
>       private LinkedList set = new LinkedList();
>
>       public CharSet(String[] set) {
>           int sz = set.length;
>           for(int i=0; i<sz; i++) {
>               add(set[i]);
>           }
>       }
>
>       public boolean contains(char ch) {
>           Iterator iterator = set.iterator();
>           boolean bool = false;
>           while(iterator.hasNext()) {
>               CharRange range = (CharRange)iterator.next();
>               if(range.isNegated()) {
>                   if(!range.inRange(ch)) {
>                       bool = true;
>                   }
>               } else {
>                   if(range.inRange(ch)) {
>                       bool = true;
>                   }
>               }
>           }
>           return bool;
>       }
>
>       public void add(String str) {
>           int sz = str.length();
>           CharRange range = null;
>           boolean end = false;
>           boolean negated = false;
>           for(int i=0; i<sz; i++) {
>               char ch = str.charAt(i);
>               if(ch == '-') {
>                   end = true;
>                   continue;
>               }
>               if(end) {
>                   range.setEnd(ch);
>                   continue;
>               }
>               if(ch == '^') {
>                   negated = true;
>                   continue;
>               }
>               range = new CharRange(ch);
>               range.setNegated(negated);
>               set.add(range);
>           }
>       }
>
>       public String toString() {
>           return set.toString();
>       }
>
>   }
>
>
>
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/Nestable.java
>
>   Index: Nestable.java
>   ===================================================================
>   package org.apache.commons.lang.exception;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.PrintWriter;
>
>   /**
>    * An interface to be implemented by {@link java.lang.Throwable}
>    * extensions which would like to be able to nest root exceptions
>    * inside themselves.
>    *
>    * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
>    * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
>    */
>   public interface Nestable
>   {
>       /**
>        * Returns the reference to the exception or error that caused the
>        * exception implementing the <code>Nestable</code> to be thrown.
>        */
>       public Throwable getCause();
>
>       /**
>        * Returns the error message of this and any nested
>        * <code>Throwable</code>.
>        *
>        * @return The error message.
>        */
>       public String getMessage();
>
>       /**
>        * Prints the stack trace of this exception to the specified print
>        * writer.  Includes inforamation from the exception--if
>        * any--which caused this exception.
>        *
>        * @param out <code>PrintWriter</code> to use for output.
>        */
>       public void printStackTrace(PrintWriter out);
>
>       /**
>        * Prints the stack trace for this exception only--root cause not
>        * included--using the provided writer.  Used by {@link
>        * org.apache.commons.lang.exception.NestableDelegate} to write
>        * individual stack traces to a buffer.  The implementation of
>        * this method should call
>        * <code>super.printStackTrace(out);</code> in most cases.
>        *
>        * @param out The writer to use.
>        */
>       public void printPartialStackTrace(PrintWriter out);
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableDelegate.java
>
>   Index: NestableDelegate.java
>   ===================================================================
>   package org.apache.commons.lang.exception;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.OutputStream;
>   import java.io.PrintStream;
>   import java.io.PrintWriter;
>   import java.io.StringWriter;
>   import java.io.Writer;
>   import java.util.LinkedList;
>   import java.util.StringTokenizer;
>
>   /**
>    * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
>    * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
>    * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
>    */
>   public class NestableDelegate
>   {
>       /**
>        * Constructor error message.
>        */
>       private static final String MUST_BE_THROWABLE =
>           "The Nestable implementation passed to the NestableDelegate(Nestable) "
>           + "constructor must extend java.lang.Throwable";
>
>       /**
>        * Holds the reference to the exception or error that caused
>        * this exception to be thrown.
>        */
>       private Nestable cause = null;
>
>       /**
>        * @param cause The Nestable implementation to get a stack trace for
>        * (<i>must</i> extend {@link java.lang.Throwable}).
>        */
>       public NestableDelegate(Nestable cause)
>       {
>           if (cause instanceof Throwable)
>           {
>               this.cause = cause;
>           }
>           else
>           {
>               throw new IllegalArgumentException(MUST_BE_THROWABLE);
>           }
>       }
>
>       /**
>        * @param baseMsg The base message to use when creating the full
>        * message.  Should be generally be called via
>        * <code>nestableHelper.getMessage(super.getMessage())</code>,
>        * where <code>super</code> is an instance of {@link
>        * java.lang.Throwable}.
>        * @return The concatenated message for this and all nested
>        * exceptions.
>        */
>       public String getMessage(String baseMsg)
>       {
>           StringBuffer msg = new StringBuffer();
>           if (baseMsg != null)
>           {
>               msg.append(baseMsg);
>           }
>
>           Throwable nestedCause = cause.getCause();
>           if (nestedCause != null)
>           {
>               String causeMsg = nestedCause.getMessage();
>               if (causeMsg != null)
>               {
>                   if (baseMsg != null)
>                   {
>                       msg.append(": ");
>                   }
>                   msg.append(causeMsg);
>               }
>
>           }
>           return (msg.length() > 0 ? msg.toString() : null);
>       }
>
>       /**
>        * Prints the stack trace of this exception the the standar error
>        * stream.
>        */
>       public void printStackTrace()
>       {
>           synchronized (System.err)
>           {
>               printStackTrace(System.err);
>           }
>       }
>
>       /**
>        * Prints the stack trace of this exception to the specified print stream.
>        *
>        * @param out <code>PrintStream</code> to use for output.
>        */
>       public void printStackTrace(PrintStream out)
>       {
>           synchronized (out)
>           {
>               PrintWriter pw = new PrintWriter(out, false);
>               printStackTrace(pw);
>               // Flush the PrintWriter before it's GC'ed.
>               pw.flush();
>           }
>       }
>
>       /**
>        * Prints the stack trace of this exception to the specified print writer.
>        *
>        * @param out <code>PrintWriter</code> to use for output.
>        */
>       public void printStackTrace(PrintWriter out)
>       {
>           synchronized (out)
>           {
>               String[] st = decompose((Throwable) cause);
>               Throwable nestedCause = cause.getCause();
>               if (nestedCause != null)
>               {
>                   if (nestedCause instanceof Nestable)
>                   {
>                       // Recurse until a non-Nestable is encountered.
>                       ((Nestable) nestedCause).printStackTrace(out);
>                   }
>                   else
>                   {
>                       String[] nst = decompose(nestedCause);
>                       for (int i = 0; i < nst.length; i++)
>                       {
>                           out.println(nst[i]);
>                       }
>                   }
>                   out.print("rethrown as ");
>               }
>
>               // Output desired frames from stack trace.
>               for (int i = 0; i < st.length; i++)
>               {
>                   out.println(st[i]);
>               }
>           }
>       }
>
>       /**
>        * Captures the stack trace associated with a <code>Throwable</code>
>        * object, decomposing it into a list of stack frames.
>        *
>        * @param t The <code>Throwable</code>.
>        * @return  An array of strings describing each stack frame.
>        */
>       private String[] decompose(Throwable t)
>       {
>           StringWriter sw = new StringWriter();
>           PrintWriter pw = new PrintWriter(sw, true);
>
>           // Avoid infinite loop between decompose() and printStackTrace().
>           if (t instanceof Nestable)
>           {
>               ((Nestable) t).printPartialStackTrace(pw);
>           }
>           else
>           {
>               t.printStackTrace(pw);
>           }
>
>           String linebreak = System.getProperty("line.separator");
>           StringTokenizer st = new StringTokenizer(sw.getBuffer().toString(),
>                                                    linebreak);
>           LinkedList list = new LinkedList();
>           while (st.hasMoreTokens())
>           {
>               list.add(st.nextToken());
>           }
>           return (String []) list.toArray(new String[] {});
>       }
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableException.java
>
>   Index: NestableException.java
>   ===================================================================
>   package org.apache.commons.lang.exception;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.OutputStream;
>   import java.io.PrintStream;
>   import java.io.PrintWriter;
>   import java.io.StringWriter;
>   import java.io.Writer;
>   import java.util.LinkedList;
>   import java.util.StringTokenizer;
>
>   /**
>    * The base class of all exceptions which can contain other exceptions.
>    *
>    * It is intended to ease the debugging by carrying on the information
>    * about the exception which was caught and provoked throwing the
>    * current exception. Catching and rethrowing may occur multiple
>    * times, and provided that all exceptions except the first one
>    * are descendands of <code>NestedException</code>, when the
>    * exception is finally printed out using any of the <code>
>    * printStackTrace()</code> methods, the stacktrace will contain
>    * the information about all exceptions thrown and caught on
>    * the way.
>    * <p> Running the following program
>    * <p><blockquote><pre>
>    *  1 import org.apache.commons.NestedException;
>    *  2
>    *  3 public class Test {
>    *  4     public static void main( String[] args ) {
>    *  5         try {
>    *  6             a();
>    *  7         } catch(Exception e) {
>    *  8             e.printStackTrace();
>    *  9         }
>    * 10      }
>    * 11
>    * 12      public static void a() throws Exception {
>    * 13          try {
>    * 14              b();
>    * 15          } catch(Exception e) {
>    * 16              throw new NestedException("foo", e);
>    * 17          }
>    * 18      }
>    * 19
>    * 20      public static void b() throws Exception {
>    * 21          try {
>    * 22              c();
>    * 23          } catch(Exception e) {
>    * 24              throw new NestedException("bar", e);
>    * 25          }
>    * 26      }
>    * 27
>    * 28      public static void c() throws Exception {
>    * 29          throw new Exception("baz");
>    * 30      }
>    * 31 }
>    * </pre></blockquote>
>    * <p>Yields the following stacktrace:
>    * <p><blockquote><pre>
>    * java.lang.Exception: baz: bar: foo
>    *    at Test.c(Test.java:29)
>    *    at Test.b(Test.java:22)
>    * rethrown as NestedException: bar
>    *    at Test.b(Test.java:24)
>    *    at Test.a(Test.java:14)
>    * rethrown as NestedException: foo
>    *    at Test.a(Test.java:16)
>    *    at Test.main(Test.java:6)
>    * </pre></blockquote><br>
>    *
>    * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
>    * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
>    * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
>    */
>   public class NestableException extends Exception implements Nestable
>   {
>       /**
>        * The helper instance which contains much of the code which we
>        * delegate to.
>        */
>       protected NestableDelegate delegate = new NestableDelegate(this);
>
>       /**
>        * Holds the reference to the exception or error that caused
>        * this exception to be thrown.
>        */
>       private Throwable cause = null;
>
>       /**
>        * Constructs a new <code>NestableException</code> without specified
>        * detail message.
>        */
>       public NestableException()
>       {
>           super();
>       }
>
>       /**
>        * Constructs a new <code>NestableException</code> with specified
>        * detail message.
>        *
>        * @param msg The error message.
>        */
>       public NestableException(String msg)
>       {
>           super(msg);
>       }
>
>       /**
>        * Constructs a new <code>NestableException</code> with specified
>        * nested <code>Throwable</code>.
>        *
>        * @param nested The exception or error that caused this exception
>        *               to be thrown.
>        */
>       public NestableException(Throwable cause)
>       {
>           super();
>           this.cause = cause;
>       }
>
>       /**
>        * Constructs a new <code>NestableException</code> with specified
>        * detail message and nested <code>Throwable</code>.
>        *
>        * @param msg    The error message.
>        * @param nested The exception or error that caused this exception
>        *               to be thrown.
>        */
>       public NestableException(String msg, Throwable cause)
>       {
>           super(msg);
>           this.cause = cause;
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#getCause()
>        */
>       public Throwable getCause()
>       {
>           return cause;
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#getMessage()
>        */
>       public String getMessage()
>       {
>           StringBuffer msg = new StringBuffer();
>           String ourMsg = super.getMessage();
>           if (ourMsg != null)
>           {
>               msg.append(ourMsg);
>           }
>           if (cause != null)
>           {
>               String causeMsg = cause.getMessage();
>               if (causeMsg != null)
>               {
>                   if (ourMsg != null)
>                   {
>                       msg.append(": ");
>                   }
>                   msg.append(causeMsg);
>               }
>
>           }
>           return (msg.length() > 0 ? msg.toString() : null);
>       }
>
>       /**
>        * Prints the stack trace of this exception the the standar error
>        * stream.
>        */
>       public void printStackTrace()
>       {
>           delegate.printStackTrace();
>       }
>
>       /**
>        * Prints the stack trace of this exception to the specified print stream.
>        *
>        * @param out <code>PrintStream</code> to use for output.
>        */
>       public void printStackTrace(PrintStream out)
>       {
>           delegate.printStackTrace(out);
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#printStackTrace(PrintWriter out)
>        */
>       public void printStackTrace(PrintWriter out)
>       {
>           delegate.printStackTrace(out);
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#printPartialStackTrace(PrintWriter out)
>        */
>       public final void printPartialStackTrace(PrintWriter out)
>       {
>           super.printStackTrace(out);
>       }
>   }
>
>
>
>   1.1                  jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception/NestableRuntimeException.java
>
>   Index: NestableRuntimeException.java
>   ===================================================================
>   package org.apache.commons.lang.exception;
>
>   /* ====================================================================
>    * The Apache Software License, Version 1.1
>    *
>    * Copyright (c) 2001 The Apache Software Foundation.  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.
>    *
>    * 3. The end-user documentation included with the redistribution,
>    *    if any, must include the following acknowledgment:
>    *       "This product includes software developed by the
>    *        Apache Software Foundation (http://www.apache.org/)."
>    *    Alternately, this acknowledgment may appear in the software itself,
>    *    if and wherever such third-party acknowledgments normally appear.
>    *
>    * 4. The names "Apache" and "Apache Software Foundation" and
>    *    "Apache Turbine" must not be used to endorse or promote products
>    *    derived from this software without prior written permission. For
>    *    written permission, please contact apache@apache.org.
>    *
>    * 5. Products derived from this software may not be called "Apache",
>    *    "Apache Turbine", nor may "Apache" appear in their name, without
>    *    prior written permission of the Apache Software Foundation.
>    *
>    * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
>    * ITS 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 consists of voluntary contributions made by many
>    * individuals on behalf of the Apache Software Foundation.  For more
>    * information on the Apache Software Foundation, please see
>    * <http://www.apache.org/>.
>    */
>
>   import java.io.OutputStream;
>   import java.io.PrintStream;
>   import java.io.PrintWriter;
>   import java.io.StringWriter;
>   import java.io.Writer;
>   import java.util.LinkedList;
>   import java.util.StringTokenizer;
>
>   /**
>    * The base class of all runtime exceptions which can contain other
>    * exceptions.
>    *
>    * @see org.apache.commons.lang.exception.NestableException
>    * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
>    * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
>    * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
>    */
>   public class NestableRuntimeException extends RuntimeException
>       implements Nestable
>   {
>       /**
>        * The helper instance which contains much of the code which we
>        * delegate to.
>        */
>       protected NestableDelegate delegate = new NestableDelegate(this);
>
>       /**
>        * Holds the reference to the exception or error that caused
>        * this exception to be thrown.
>        */
>       private Throwable cause = null;
>
>       /**
>        * Constructs a new <code>NestableRuntimeException</code> without specified
>        * detail message.
>        */
>       public NestableRuntimeException()
>       {
>           super();
>       }
>
>       /**
>        * Constructs a new <code>NestableRuntimeException</code> with specified
>        * detail message.
>        *
>        * @param msg The error message.
>        */
>       public NestableRuntimeException(String msg)
>       {
>           super(msg);
>       }
>
>       /**
>        * Constructs a new <code>NestableRuntimeException</code> with specified
>        * nested <code>Throwable</code>.
>        *
>        * @param nested The exception or error that caused this exception
>        *               to be thrown.
>        */
>       public NestableRuntimeException(Throwable cause)
>       {
>           super();
>           this.cause = cause;
>       }
>
>       /**
>        * Constructs a new <code>NestableRuntimeException</code> with specified
>        * detail message and nested <code>Throwable</code>.
>        *
>        * @param msg    The error message.
>        * @param nested The exception or error that caused this exception
>        *               to be thrown.
>        */
>       public NestableRuntimeException(String msg, Throwable cause)
>       {
>           super(msg);
>           this.cause = cause;
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#getCause()
>        */
>       public Throwable getCause()
>       {
>           return cause;
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#getMessage()
>        */
>       public String getMessage()
>       {
>           StringBuffer msg = new StringBuffer();
>           String ourMsg = super.getMessage();
>           if (ourMsg != null)
>           {
>               msg.append(ourMsg);
>           }
>           if (cause != null)
>           {
>               String causeMsg = cause.getMessage();
>               if (causeMsg != null)
>               {
>                   if (ourMsg != null)
>                   {
>                       msg.append(": ");
>                   }
>                   msg.append(causeMsg);
>               }
>
>           }
>           return (msg.length() > 0 ? msg.toString() : null);
>       }
>
>       /**
>        * Prints the stack trace of this exception the the standar error
>        * stream.
>        */
>       public void printStackTrace()
>       {
>           delegate.printStackTrace();
>       }
>
>       /**
>        * Prints the stack trace of this exception to the specified print stream.
>        *
>        * @param out <code>PrintStream</code> to use for output.
>        */
>       public void printStackTrace(PrintStream out)
>       {
>           delegate.printStackTrace(out);
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#printStackTrace(PrintWriter out)
>        */
>       public void printStackTrace(PrintWriter out)
>       {
>           delegate.printStackTrace(out);
>       }
>
>       /**
>        * @see org.apache.commons.lang.exception.Nestable#printPartialStackTrace(PrintWriter out)
>        */
>       public final void printPartialStackTrace(PrintWriter out)
>       {
>           super.printStackTrace(out);
>       }
>   }
>
>
>
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>