commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bay...@apache.org
Subject cvs commit: jakarta-commons-sandbox/lang/src/java/org/apache/commons/lang/exception Nestable.java NestableDelegate.java NestableException.java NestableRuntimeException.java
Date Fri, 22 Feb 2002 05:57:15 GMT
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:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message