You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/09/25 21:11:48 UTC

svn commit: rev 47215 - in incubator/directory/ldap/trunk/common: . src/antlr src/java/org/apache/ldap/common src/java/org/apache/ldap/common/filter src/java/org/apache/ldap/common/ldif src/java/org/apache/ldap/common/message src/java/org/apache/ldap/common/name src/java/org/apache/ldap/common/util

Author: akarasulu
Date: Sat Sep 25 12:11:47 2004
New Revision: 47215

Added:
   incubator/directory/ldap/trunk/common/jakarta-commons-forks.txt   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ArrayUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/BooleanUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ClassUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Enum.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EnumUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EqualsBuilder.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ExceptionUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/HashCodeBuilder.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/MultiMap.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Nestable.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableDelegate.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableError.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableException.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableRuntimeException.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ObjectUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ReflectionToStringBuilder.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/SystemUtils.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringBuilder.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringStyle.java   (contents, props changed)
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ValuedEnum.java   (contents, props changed)
Modified:
   incubator/directory/ldap/trunk/common/project.xml
   incubator/directory/ldap/trunk/common/src/antlr/dnparser.g
   incubator/directory/ldap/trunk/common/src/antlr/filter.g
   incubator/directory/ldap/trunk/common/src/antlr/typelexer.g
   incubator/directory/ldap/trunk/common/src/antlr/valuelexer.g
   incubator/directory/ldap/trunk/common/src/antlr/valueparser.g
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/AbstractLockable.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposer.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposerImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindRequestImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindResponseImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/DerefAliasesEnum.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedRequestImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedResponseImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/LockableAttributesImpl.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/MessageTypeEnum.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ResultCodeEnum.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ScopeEnum.java
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/name/DnParser.java
Log:
removed dependency on commons lang and collections

Added: incubator/directory/ldap/trunk/common/jakarta-commons-forks.txt
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/jakarta-commons-forks.txt	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,41 @@
+In an effort to reduce the amount of jars users have to include during
+runtime we have forked some of the commons classes that we use or depend
+upon.  The following list of classes have been forked.  We did not want
+to fork these classes but users just don't want too many dependencies.
+We appologise for this temporary impediment to reuse.
+
+The use of these classes are really for trivial means.  Much of the 
+functionality can actually be replaced all together with a tiny bit of
+effort to remove most of the forked classes here.  So expect many of 
+these forked classes to gradually disappear. 
+
+src/java/org/apache/ldap/common/util/ArrayUtils.java
+src/java/org/apache/ldap/common/util/BooleanUtils.java
+src/java/org/apache/ldap/common/util/EqualsBuilder.java
+src/java/org/apache/ldap/common/util/Enum.java
+src/java/org/apache/ldap/common/util/SystemUtils.java
+src/java/org/apache/ldap/common/util/ValuedEnum.java
+src/java/org/apache/ldap/common/util/NestableError.java
+src/java/org/apache/ldap/common/util/NestableException.java
+src/java/org/apache/ldap/common/util/ExceptionUtils.java
+src/java/org/apache/ldap/common/util/ToStringBuilder.java
+src/java/org/apache/ldap/common/util/NestableRuntimeException.java
+src/java/org/apache/ldap/common/util/HashCodeBuilder.java
+src/java/org/apache/ldap/common/util/EnumUtils.java
+src/java/org/apache/ldap/common/util/ClassUtils.java
+src/java/org/apache/ldap/common/util/ObjectUtils.java
+src/java/org/apache/ldap/common/util/NestableDelegate.java
+src/java/org/apache/ldap/common/util/MultiMap.java
+src/java/org/apache/ldap/common/util/ToStringStyle.java
+src/java/org/apache/ldap/common/util/ReflectionToStringBuilder.java
+src/java/org/apache/ldap/common/util/Nestable.java
+
+At this point we only have two runtime dependencies.  Regexp and the
+antlr runtime.  Eventually as changes are made to the backend we will
+move away from using Regexp to using the regular expressions packaged
+with the 1.4 JDK.  The best however would be to have a single commons-logging
+like wrapper around the various RE implementations out there.
+
+Cheers,
+Alex
+ 

Modified: incubator/directory/ldap/trunk/common/project.xml
==============================================================================
--- incubator/directory/ldap/trunk/common/project.xml	(original)
+++ incubator/directory/ldap/trunk/common/project.xml	Sat Sep 25 12:11:47 2004
@@ -29,29 +29,15 @@
 	    Common LDAP packages used by clients and servers.
     </shortDescription>
     
-	<dependencies>
-
-		<dependency>
-			<groupId>commons-collections</groupId>
-			<artifactId>commons-collections</artifactId>
-			<version>2.1</version>
-			<url>http://jakarta.apache.org/commons/collections</url>
-		</dependency>
+    <dependencies>
 
     <dependency>
-      <groupId>commons-lang</groupId>
-      <artifactId>commons-lang</artifactId>
-      <version>2.0</version>
-      <url>http://jakarta.apache.org/commons/lang</url>
+      <groupId>regexp</groupId>
+      <artifactId>regexp</artifactId>
+      <version>1.2</version>
+      <url>http://jakarta.apache.org/regexp/index.html</url>
     </dependency>
 
-		<dependency>
-			<groupId>regexp</groupId>
-			<artifactId>regexp</artifactId>
-			<version>1.2</version>
-			<url>http://jakarta.apache.org/regexp/index.html</url>
-		</dependency>
-
     <dependency>
       <groupId>antlr</groupId>
       <artifactId>antlr</artifactId>
@@ -72,7 +58,7 @@
       <version>SNAPSHOT</version>
     </dependency>
 
-	</dependencies>
+    </dependencies>
     
     <build>
       <nagEmailAddress>directory-dev@incubator.apache.org</nagEmailAddress>

Modified: incubator/directory/ldap/trunk/common/src/antlr/dnparser.g
==============================================================================
--- incubator/directory/ldap/trunk/common/src/antlr/dnparser.g	(original)
+++ incubator/directory/ldap/trunk/common/src/antlr/dnparser.g	Sat Sep 25 12:11:47 2004
@@ -1,59 +1,17 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
  *
- * Copyright (c) 2000 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" 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",
- *    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/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 header {

Modified: incubator/directory/ldap/trunk/common/src/antlr/filter.g
==============================================================================
--- incubator/directory/ldap/trunk/common/src/antlr/filter.g	(original)
+++ incubator/directory/ldap/trunk/common/src/antlr/filter.g	Sat Sep 25 12:11:47 2004
@@ -27,8 +27,8 @@
  *
  */
 /*
- * Keep the semicolon right next to org.apache.ldap.common.name.filter or 
- * else there will be a bug that comes into the foreground in the new antlr 
+ * Keep the semicolon right next to org.apache.ldap.common.name.filter or
+ * else there will be a bug that comes into the foreground in the new antlr
  * release.
  */
 package org.apache.ldap.common.filter;

Modified: incubator/directory/ldap/trunk/common/src/antlr/typelexer.g
==============================================================================
--- incubator/directory/ldap/trunk/common/src/antlr/typelexer.g	(original)
+++ incubator/directory/ldap/trunk/common/src/antlr/typelexer.g	Sat Sep 25 12:11:47 2004
@@ -1,61 +1,18 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
  *
- * Copyright (c) 2000 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" 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",
- *    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/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
-
 header {
 	/*
 	 * Keep the semicolon right next to org.apache.ldap.common.name or else there

Modified: incubator/directory/ldap/trunk/common/src/antlr/valuelexer.g
==============================================================================
--- incubator/directory/ldap/trunk/common/src/antlr/valuelexer.g	(original)
+++ incubator/directory/ldap/trunk/common/src/antlr/valuelexer.g	Sat Sep 25 12:11:47 2004
@@ -1,61 +1,18 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
  *
- * Copyright (c) 2000 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" 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",
- *    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/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
-
 header {
 	/*
 	 * Keep the semicolon right next to org.apache.ldap.common.name or else there

Modified: incubator/directory/ldap/trunk/common/src/antlr/valueparser.g
==============================================================================
--- incubator/directory/ldap/trunk/common/src/antlr/valueparser.g	(original)
+++ incubator/directory/ldap/trunk/common/src/antlr/valueparser.g	Sat Sep 25 12:11:47 2004
@@ -22,7 +22,7 @@
 package org.apache.ldap.common.name;
 
 import javax.naming.NamingException ;
-import org.apache.commons.lang.exception.NestableRuntimeException ;
+import org.apache.ldap.common.util.NestableRuntimeException ;
 }
 
 class antlrValueParser extends Parser ;

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/AbstractLockable.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/AbstractLockable.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/AbstractLockable.java	Sat Sep 25 12:11:47 2004
@@ -1,217 +1,18 @@
-/*
- *                                 Apache License
- *                           Version 2.0, January 2004
- *                        http://www.apache.org/licenses/
- *
- *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- *
- *   1. Definitions.
- *
- *      "License" shall mean the terms and conditions for use, reproduction,
- *      and distribution as defined by Sections 1 through 9 of this document.
- *
- *      "Licensor" shall mean the copyright owner or entity authorized by
- *      the copyright owner that is granting the License.
- *
- *      "Legal Entity" shall mean the union of the acting entity and all
- *      other entities that control, are controlled by, or are under common
- *      control with that entity. For the purposes of this definition,
- *      "control" means (i) the power, direct or indirect, to cause the
- *      direction or management of such entity, whether by contract or
- *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
- *      outstanding shares, or (iii) beneficial ownership of such entity.
- *
- *      "You" (or "Your") shall mean an individual or Legal Entity
- *      exercising permissions granted by this License.
- *
- *      "Source" form shall mean the preferred form for making modifications,
- *      including but not limited to software source code, documentation
- *      source, and configuration files.
- *
- *      "Object" form shall mean any form resulting from mechanical
- *      transformation or translation of a Source form, including but
- *      not limited to compiled object code, generated documentation,
- *      and conversions to other media types.
- *
- *      "Work" shall mean the work of authorship, whether in Source or
- *      Object form, made available under the License, as indicated by a
- *      copyright notice that is included in or attached to the work
- *      (an example is provided in the Appendix below).
- *
- *      "Derivative Works" shall mean any work, whether in Source or Object
- *      form, that is based on (or derived from) the Work and for which the
- *      editorial revisions, annotations, elaborations, or other modifications
- *      represent, as a whole, an original work of authorship. For the purposes
- *      of this License, Derivative Works shall not include works that remain
- *      separable from, or merely link (or bind by name) to the interfaces of,
- *      the Work and Derivative Works thereof.
- *
- *      "Contribution" shall mean any work of authorship, including
- *      the original version of the Work and any modifications or additions
- *      to that Work or Derivative Works thereof, that is intentionally
- *      submitted to Licensor for inclusion in the Work by the copyright owner
- *      or by an individual or Legal Entity authorized to submit on behalf of
- *      the copyright owner. For the purposes of this definition, "submitted"
- *      means any form of electronic, verbal, or written communication sent
- *      to the Licensor or its representatives, including but not limited to
- *      communication on electronic mailing lists, source code control systems,
- *      and issue tracking systems that are managed by, or on behalf of, the
- *      Licensor for the purpose of discussing and improving the Work, but
- *      excluding communication that is conspicuously marked or otherwise
- *      designated in writing by the copyright owner as "Not a Contribution."
- *
- *      "Contributor" shall mean Licensor and any individual or Legal Entity
- *      on behalf of whom a Contribution has been received by Licensor and
- *      subsequently incorporated within the Work.
- *
- *   2. Grant of Copyright License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      copyright license to reproduce, prepare Derivative Works of,
- *      publicly display, publicly perform, sublicense, and distribute the
- *      Work and such Derivative Works in Source or Object form.
- *
- *   3. Grant of Patent License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      (except as stated in this section) patent license to make, have made,
- *      use, offer to sell, sell, import, and otherwise transfer the Work,
- *      where such license applies only to those patent claims licensable
- *      by such Contributor that are necessarily infringed by their
- *      Contribution(s) alone or by combination of their Contribution(s)
- *      with the Work to which such Contribution(s) was submitted. If You
- *      institute patent litigation against any entity (including a
- *      cross-claim or counterclaim in a lawsuit) alleging that the Work
- *      or a Contribution incorporated within the Work constitutes direct
- *      or contributory patent infringement, then any patent licenses
- *      granted to You under this License for that Work shall terminate
- *      as of the date such litigation is filed.
- *
- *   4. Redistribution. You may reproduce and distribute copies of the
- *      Work or Derivative Works thereof in any medium, with or without
- *      modifications, and in Source or Object form, provided that You
- *      meet the following conditions:
- *
- *      (a) You must give any other recipients of the Work or
- *          Derivative Works a copy of this License; and
- *
- *      (b) You must cause any modified files to carry prominent notices
- *          stating that You changed the files; and
- *
- *      (c) You must retain, in the Source form of any Derivative Works
- *          that You distribute, all copyright, patent, trademark, and
- *          attribution notices from the Source form of the Work,
- *          excluding those notices that do not pertain to any part of
- *          the Derivative Works; and
- *
- *      (d) If the Work includes a "NOTICE" text file as part of its
- *          distribution, then any Derivative Works that You distribute must
- *          include a readable copy of the attribution notices contained
- *          within such NOTICE file, excluding those notices that do not
- *          pertain to any part of the Derivative Works, in at least one
- *          of the following places: within a NOTICE text file distributed
- *          as part of the Derivative Works; within the Source form or
- *          documentation, if provided along with the Derivative Works; or,
- *          within a display generated by the Derivative Works, if and
- *          wherever such third-party notices normally appear. The contents
- *          of the NOTICE file are for informational purposes only and
- *          do not modify the License. You may add Your own attribution
- *          notices within Derivative Works that You distribute, alongside
- *          or as an addendum to the NOTICE text from the Work, provided
- *          that such additional attribution notices cannot be construed
- *          as modifying the License.
- *
- *      You may add Your own copyright statement to Your modifications and
- *      may provide additional or different license terms and conditions
- *      for use, reproduction, or distribution of Your modifications, or
- *      for any such Derivative Works as a whole, provided Your use,
- *      reproduction, and distribution of the Work otherwise complies with
- *      the conditions stated in this License.
- *
- *   5. Submission of Contributions. Unless You explicitly state otherwise,
- *      any Contribution intentionally submitted for inclusion in the Work
- *      by You to the Licensor shall be under the terms and conditions of
- *      this License, without any additional terms or conditions.
- *      Notwithstanding the above, nothing herein shall supersede or modify
- *      the terms of any separate license agreement you may have executed
- *      with Licensor regarding such Contributions.
- *
- *   6. Trademarks. This License does not grant permission to use the trade
- *      names, trademarks, service marks, or product names of the Licensor,
- *      except as required for reasonable and customary use in describing the
- *      origin of the Work and reproducing the content of the NOTICE file.
- *
- *   7. Disclaimer of Warranty. Unless required by applicable law or
- *      agreed to in writing, Licensor provides the Work (and each
- *      Contributor provides its Contributions) on an "AS IS" BASIS,
- *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- *      implied, including, without limitation, any warranties or conditions
- *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- *      PARTICULAR PURPOSE. You are solely responsible for determining the
- *      appropriateness of using or redistributing the Work and assume any
- *      risks associated with Your exercise of permissions under this License.
- *
- *   8. Limitation of Liability. In no event and under no legal theory,
- *      whether in tort (including negligence), contract, or otherwise,
- *      unless required by applicable law (such as deliberate and grossly
- *      negligent acts) or agreed to in writing, shall any Contributor be
- *      liable to You for damages, including any direct, indirect, special,
- *      incidental, or consequential damages of any character arising as a
- *      result of this License or out of the use or inability to use the
- *      Work (including but not limited to damages for loss of goodwill,
- *      work stoppage, computer failure or malfunction, or any and all
- *      other commercial damages or losses), even if such Contributor
- *      has been advised of the possibility of such damages.
- *
- *   9. Accepting Warranty or Additional Liability. While redistributing
- *      the Work or Derivative Works thereof, You may choose to offer,
- *      and charge a fee for, acceptance of support, warranty, indemnity,
- *      or other liability obligations and/or rights consistent with this
- *      License. However, in accepting such obligations, You may act only
- *      on Your own behalf and on Your sole responsibility, not on behalf
- *      of any other Contributor, and only if You agree to indemnify,
- *      defend, and hold each Contributor harmless for any liability
- *      incurred by, or claims asserted against, such Contributor by reason
- *      of your accepting any such warranty or additional liability.
- *
- *   END OF TERMS AND CONDITIONS
- *
- *   APPENDIX: How to apply the Apache License to your work.
- *
- *      To apply the Apache License to your work, attach the following
- *      boilerplate notice, with the fields enclosed by brackets "[]"
- *      replaced with your own identifying information. (Don't include
- *      the brackets!)  The text should be enclosed in the appropriate
- *      comment syntax for the file format. We also recommend that a
- *      file or class name and description of purpose be included on the
- *      same "printed page" as the copyright notice for easier
- *      identification within third-party archives.
- *
- *   Copyright [yyyy] [name of copyright owner]
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
-
 /*
- * $Id: AbstractLockable.java,v 1.8 2003/09/18 22:42:31 akarasulu Exp $
+ * Copyright 2002-2004 The Apache Software Foundation.
  *
- * -- (c) LDAPd Group                                                    --
- * -- Please refer to the LICENSE.txt file in the root directory of      --
- * -- any LDAPd project for copyright and distribution information.      --
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
-
 package org.apache.ldap.common ;
 
 

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java	Sat Sep 25 12:11:47 2004
@@ -21,11 +21,10 @@
 import java.text.ParseException ;
 import java.io.PipedInputStream ;
 import java.io.PipedOutputStream ;
-
-import org.apache.commons.lang.exception.ExceptionUtils ;
 
+import org.apache.ldap.common.util.ExceptionUtils;
 import antlr.RecognitionException ;
-import antlr.TokenStreamException ;
+import antlr.TokenStreamException ;
 
 
 /**
@@ -37,7 +36,7 @@
  */
 public class FilterParserImpl
     implements FilterParser
-{
+{
     private FilterParserMonitor monitor = new FilterParserMonitorAdapter() ;
     /** The antlr generated parser */
     private antlrFilterParser m_parser = null ;
@@ -91,7 +90,7 @@
         }
 
         if ( null == monitor )
-        {
+        {
             monitor = new FilterParserMonitorAdapter() ;
         }
 
@@ -121,15 +120,15 @@
         }
 
         return l_root ;
-    }
-    
-    
-    /* (non-Javadoc)
-     * @see org.apache.ldap.common.filter.FilterParser#setFilterParserMonitor(
-     * org.apache.ldap.common.filter.FilterParserMonitor)
-     */
-    public void setFilterParserMonitor( FilterParserMonitor monitor )
-    {
-        this.monitor = monitor ;
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see org.apache.ldap.common.filter.FilterParser#setFilterParserMonitor(
+     * org.apache.ldap.common.filter.FilterParserMonitor)
+     */
+    public void setFilterParserMonitor( FilterParserMonitor monitor )
+    {
+        this.monitor = monitor ;
     }
 }

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposer.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposer.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposer.java	Sat Sep 25 12:11:47 2004
@@ -1,207 +1,207 @@
-/*
- *                                 Apache License
- *                           Version 2.0, January 2004
- *                        http://www.apache.org/licenses/
- *
- *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- *
- *   1. Definitions.
- *
- *      "License" shall mean the terms and conditions for use, reproduction,
- *      and distribution as defined by Sections 1 through 9 of this document.
- *
- *      "Licensor" shall mean the copyright owner or entity authorized by
- *      the copyright owner that is granting the License.
- *
- *      "Legal Entity" shall mean the union of the acting entity and all
- *      other entities that control, are controlled by, or are under common
- *      control with that entity. For the purposes of this definition,
- *      "control" means (i) the power, direct or indirect, to cause the
- *      direction or management of such entity, whether by contract or
- *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
- *      outstanding shares, or (iii) beneficial ownership of such entity.
- *
- *      "You" (or "Your") shall mean an individual or Legal Entity
- *      exercising permissions granted by this License.
- *
- *      "Source" form shall mean the preferred form for making modifications,
- *      including but not limited to software source code, documentation
- *      source, and configuration files.
- *
- *      "Object" form shall mean any form resulting from mechanical
- *      transformation or translation of a Source form, including but
- *      not limited to compiled object code, generated documentation,
- *      and conversions to other media types.
- *
- *      "Work" shall mean the work of authorship, whether in Source or
- *      Object form, made available under the License, as indicated by a
- *      copyright notice that is included in or attached to the work
- *      (an example is provided in the Appendix below).
- *
- *      "Derivative Works" shall mean any work, whether in Source or Object
- *      form, that is based on (or derived from) the Work and for which the
- *      editorial revisions, annotations, elaborations, or other modifications
- *      represent, as a whole, an original work of authorship. For the purposes
- *      of this License, Derivative Works shall not include works that remain
- *      separable from, or merely link (or bind by name) to the interfaces of,
- *      the Work and Derivative Works thereof.
- *
- *      "Contribution" shall mean any work of authorship, including
- *      the original version of the Work and any modifications or additions
- *      to that Work or Derivative Works thereof, that is intentionally
- *      submitted to Licensor for inclusion in the Work by the copyright owner
- *      or by an individual or Legal Entity authorized to submit on behalf of
- *      the copyright owner. For the purposes of this definition, "submitted"
- *      means any form of electronic, verbal, or written communication sent
- *      to the Licensor or its representatives, including but not limited to
- *      communication on electronic mailing lists, source code control systems,
- *      and issue tracking systems that are managed by, or on behalf of, the
- *      Licensor for the purpose of discussing and improving the Work, but
- *      excluding communication that is conspicuously marked or otherwise
- *      designated in writing by the copyright owner as "Not a Contribution."
- *
- *      "Contributor" shall mean Licensor and any individual or Legal Entity
- *      on behalf of whom a Contribution has been received by Licensor and
- *      subsequently incorporated within the Work.
- *
- *   2. Grant of Copyright License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      copyright license to reproduce, prepare Derivative Works of,
- *      publicly display, publicly perform, sublicense, and distribute the
- *      Work and such Derivative Works in Source or Object form.
- *
- *   3. Grant of Patent License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      (except as stated in this section) patent license to make, have made,
- *      use, offer to sell, sell, import, and otherwise transfer the Work,
- *      where such license applies only to those patent claims licensable
- *      by such Contributor that are necessarily infringed by their
- *      Contribution(s) alone or by combination of their Contribution(s)
- *      with the Work to which such Contribution(s) was submitted. If You
- *      institute patent litigation against any entity (including a
- *      cross-claim or counterclaim in a lawsuit) alleging that the Work
- *      or a Contribution incorporated within the Work constitutes direct
- *      or contributory patent infringement, then any patent licenses
- *      granted to You under this License for that Work shall terminate
- *      as of the date such litigation is filed.
- *
- *   4. Redistribution. You may reproduce and distribute copies of the
- *      Work or Derivative Works thereof in any medium, with or without
- *      modifications, and in Source or Object form, provided that You
- *      meet the following conditions:
- *
- *      (a) You must give any other recipients of the Work or
- *          Derivative Works a copy of this License; and
- *
- *      (b) You must cause any modified files to carry prominent notices
- *          stating that You changed the files; and
- *
- *      (c) You must retain, in the Source form of any Derivative Works
- *          that You distribute, all copyright, patent, trademark, and
- *          attribution notices from the Source form of the Work,
- *          excluding those notices that do not pertain to any part of
- *          the Derivative Works; and
- *
- *      (d) If the Work includes a "NOTICE" text file as part of its
- *          distribution, then any Derivative Works that You distribute must
- *          include a readable copy of the attribution notices contained
- *          within such NOTICE file, excluding those notices that do not
- *          pertain to any part of the Derivative Works, in at least one
- *          of the following places: within a NOTICE text file distributed
- *          as part of the Derivative Works; within the Source form or
- *          documentation, if provided along with the Derivative Works; or,
- *          within a display generated by the Derivative Works, if and
- *          wherever such third-party notices normally appear. The contents
- *          of the NOTICE file are for informational purposes only and
- *          do not modify the License. You may add Your own attribution
- *          notices within Derivative Works that You distribute, alongside
- *          or as an addendum to the NOTICE text from the Work, provided
- *          that such additional attribution notices cannot be construed
- *          as modifying the License.
- *
- *      You may add Your own copyright statement to Your modifications and
- *      may provide additional or different license terms and conditions
- *      for use, reproduction, or distribution of Your modifications, or
- *      for any such Derivative Works as a whole, provided Your use,
- *      reproduction, and distribution of the Work otherwise complies with
- *      the conditions stated in this License.
- *
- *   5. Submission of Contributions. Unless You explicitly state otherwise,
- *      any Contribution intentionally submitted for inclusion in the Work
- *      by You to the Licensor shall be under the terms and conditions of
- *      this License, without any additional terms or conditions.
- *      Notwithstanding the above, nothing herein shall supersede or modify
- *      the terms of any separate license agreement you may have executed
- *      with Licensor regarding such Contributions.
- *
- *   6. Trademarks. This License does not grant permission to use the trade
- *      names, trademarks, service marks, or product names of the Licensor,
- *      except as required for reasonable and customary use in describing the
- *      origin of the Work and reproducing the content of the NOTICE file.
- *
- *   7. Disclaimer of Warranty. Unless required by applicable law or
- *      agreed to in writing, Licensor provides the Work (and each
- *      Contributor provides its Contributions) on an "AS IS" BASIS,
- *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- *      implied, including, without limitation, any warranties or conditions
- *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- *      PARTICULAR PURPOSE. You are solely responsible for determining the
- *      appropriateness of using or redistributing the Work and assume any
- *      risks associated with Your exercise of permissions under this License.
- *
- *   8. Limitation of Liability. In no event and under no legal theory,
- *      whether in tort (including negligence), contract, or otherwise,
- *      unless required by applicable law (such as deliberate and grossly
- *      negligent acts) or agreed to in writing, shall any Contributor be
- *      liable to You for damages, including any direct, indirect, special,
- *      incidental, or consequential damages of any character arising as a
- *      result of this License or out of the use or inability to use the
- *      Work (including but not limited to damages for loss of goodwill,
- *      work stoppage, computer failure or malfunction, or any and all
- *      other commercial damages or losses), even if such Contributor
- *      has been advised of the possibility of such damages.
- *
- *   9. Accepting Warranty or Additional Liability. While redistributing
- *      the Work or Derivative Works thereof, You may choose to offer,
- *      and charge a fee for, acceptance of support, warranty, indemnity,
- *      or other liability obligations and/or rights consistent with this
- *      License. However, in accepting such obligations, You may act only
- *      on Your own behalf and on Your sole responsibility, not on behalf
- *      of any other Contributor, and only if You agree to indemnify,
- *      defend, and hold each Contributor harmless for any liability
- *      incurred by, or claims asserted against, such Contributor by reason
- *      of your accepting any such warranty or additional liability.
- *
- *   END OF TERMS AND CONDITIONS
- *
- *   APPENDIX: How to apply the Apache License to your work.
- *
- *      To apply the Apache License to your work, attach the following
- *      boilerplate notice, with the fields enclosed by brackets "[]"
- *      replaced with your own identifying information. (Don't include
- *      the brackets!)  The text should be enclosed in the appropriate
- *      comment syntax for the file format. We also recommend that a
- *      file or class name and description of purpose be included on the
- *      same "printed page" as the copyright notice for easier
- *      identification within third-party archives.
- *
- *   Copyright [yyyy] [name of copyright owner]
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
+/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 
 /*
  * $Id: LdifComposer.java,v 1.4 2003/07/31 21:44:49 akarasulu Exp $
@@ -216,7 +216,7 @@
 package org.apache.ldap.common.ldif ;
 
 
-import org.apache.commons.collections.MultiMap ;
+import org.apache.ldap.common.util.MultiMap ;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposerImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposerImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifComposerImpl.java	Sat Sep 25 12:11:47 2004
@@ -1,207 +1,207 @@
-/*
- *                                 Apache License
- *                           Version 2.0, January 2004
- *                        http://www.apache.org/licenses/
- *
- *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- *
- *   1. Definitions.
- *
- *      "License" shall mean the terms and conditions for use, reproduction,
- *      and distribution as defined by Sections 1 through 9 of this document.
- *
- *      "Licensor" shall mean the copyright owner or entity authorized by
- *      the copyright owner that is granting the License.
- *
- *      "Legal Entity" shall mean the union of the acting entity and all
- *      other entities that control, are controlled by, or are under common
- *      control with that entity. For the purposes of this definition,
- *      "control" means (i) the power, direct or indirect, to cause the
- *      direction or management of such entity, whether by contract or
- *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
- *      outstanding shares, or (iii) beneficial ownership of such entity.
- *
- *      "You" (or "Your") shall mean an individual or Legal Entity
- *      exercising permissions granted by this License.
- *
- *      "Source" form shall mean the preferred form for making modifications,
- *      including but not limited to software source code, documentation
- *      source, and configuration files.
- *
- *      "Object" form shall mean any form resulting from mechanical
- *      transformation or translation of a Source form, including but
- *      not limited to compiled object code, generated documentation,
- *      and conversions to other media types.
- *
- *      "Work" shall mean the work of authorship, whether in Source or
- *      Object form, made available under the License, as indicated by a
- *      copyright notice that is included in or attached to the work
- *      (an example is provided in the Appendix below).
- *
- *      "Derivative Works" shall mean any work, whether in Source or Object
- *      form, that is based on (or derived from) the Work and for which the
- *      editorial revisions, annotations, elaborations, or other modifications
- *      represent, as a whole, an original work of authorship. For the purposes
- *      of this License, Derivative Works shall not include works that remain
- *      separable from, or merely link (or bind by name) to the interfaces of,
- *      the Work and Derivative Works thereof.
- *
- *      "Contribution" shall mean any work of authorship, including
- *      the original version of the Work and any modifications or additions
- *      to that Work or Derivative Works thereof, that is intentionally
- *      submitted to Licensor for inclusion in the Work by the copyright owner
- *      or by an individual or Legal Entity authorized to submit on behalf of
- *      the copyright owner. For the purposes of this definition, "submitted"
- *      means any form of electronic, verbal, or written communication sent
- *      to the Licensor or its representatives, including but not limited to
- *      communication on electronic mailing lists, source code control systems,
- *      and issue tracking systems that are managed by, or on behalf of, the
- *      Licensor for the purpose of discussing and improving the Work, but
- *      excluding communication that is conspicuously marked or otherwise
- *      designated in writing by the copyright owner as "Not a Contribution."
- *
- *      "Contributor" shall mean Licensor and any individual or Legal Entity
- *      on behalf of whom a Contribution has been received by Licensor and
- *      subsequently incorporated within the Work.
- *
- *   2. Grant of Copyright License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      copyright license to reproduce, prepare Derivative Works of,
- *      publicly display, publicly perform, sublicense, and distribute the
- *      Work and such Derivative Works in Source or Object form.
- *
- *   3. Grant of Patent License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      (except as stated in this section) patent license to make, have made,
- *      use, offer to sell, sell, import, and otherwise transfer the Work,
- *      where such license applies only to those patent claims licensable
- *      by such Contributor that are necessarily infringed by their
- *      Contribution(s) alone or by combination of their Contribution(s)
- *      with the Work to which such Contribution(s) was submitted. If You
- *      institute patent litigation against any entity (including a
- *      cross-claim or counterclaim in a lawsuit) alleging that the Work
- *      or a Contribution incorporated within the Work constitutes direct
- *      or contributory patent infringement, then any patent licenses
- *      granted to You under this License for that Work shall terminate
- *      as of the date such litigation is filed.
- *
- *   4. Redistribution. You may reproduce and distribute copies of the
- *      Work or Derivative Works thereof in any medium, with or without
- *      modifications, and in Source or Object form, provided that You
- *      meet the following conditions:
- *
- *      (a) You must give any other recipients of the Work or
- *          Derivative Works a copy of this License; and
- *
- *      (b) You must cause any modified files to carry prominent notices
- *          stating that You changed the files; and
- *
- *      (c) You must retain, in the Source form of any Derivative Works
- *          that You distribute, all copyright, patent, trademark, and
- *          attribution notices from the Source form of the Work,
- *          excluding those notices that do not pertain to any part of
- *          the Derivative Works; and
- *
- *      (d) If the Work includes a "NOTICE" text file as part of its
- *          distribution, then any Derivative Works that You distribute must
- *          include a readable copy of the attribution notices contained
- *          within such NOTICE file, excluding those notices that do not
- *          pertain to any part of the Derivative Works, in at least one
- *          of the following places: within a NOTICE text file distributed
- *          as part of the Derivative Works; within the Source form or
- *          documentation, if provided along with the Derivative Works; or,
- *          within a display generated by the Derivative Works, if and
- *          wherever such third-party notices normally appear. The contents
- *          of the NOTICE file are for informational purposes only and
- *          do not modify the License. You may add Your own attribution
- *          notices within Derivative Works that You distribute, alongside
- *          or as an addendum to the NOTICE text from the Work, provided
- *          that such additional attribution notices cannot be construed
- *          as modifying the License.
- *
- *      You may add Your own copyright statement to Your modifications and
- *      may provide additional or different license terms and conditions
- *      for use, reproduction, or distribution of Your modifications, or
- *      for any such Derivative Works as a whole, provided Your use,
- *      reproduction, and distribution of the Work otherwise complies with
- *      the conditions stated in this License.
- *
- *   5. Submission of Contributions. Unless You explicitly state otherwise,
- *      any Contribution intentionally submitted for inclusion in the Work
- *      by You to the Licensor shall be under the terms and conditions of
- *      this License, without any additional terms or conditions.
- *      Notwithstanding the above, nothing herein shall supersede or modify
- *      the terms of any separate license agreement you may have executed
- *      with Licensor regarding such Contributions.
- *
- *   6. Trademarks. This License does not grant permission to use the trade
- *      names, trademarks, service marks, or product names of the Licensor,
- *      except as required for reasonable and customary use in describing the
- *      origin of the Work and reproducing the content of the NOTICE file.
- *
- *   7. Disclaimer of Warranty. Unless required by applicable law or
- *      agreed to in writing, Licensor provides the Work (and each
- *      Contributor provides its Contributions) on an "AS IS" BASIS,
- *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- *      implied, including, without limitation, any warranties or conditions
- *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- *      PARTICULAR PURPOSE. You are solely responsible for determining the
- *      appropriateness of using or redistributing the Work and assume any
- *      risks associated with Your exercise of permissions under this License.
- *
- *   8. Limitation of Liability. In no event and under no legal theory,
- *      whether in tort (including negligence), contract, or otherwise,
- *      unless required by applicable law (such as deliberate and grossly
- *      negligent acts) or agreed to in writing, shall any Contributor be
- *      liable to You for damages, including any direct, indirect, special,
- *      incidental, or consequential damages of any character arising as a
- *      result of this License or out of the use or inability to use the
- *      Work (including but not limited to damages for loss of goodwill,
- *      work stoppage, computer failure or malfunction, or any and all
- *      other commercial damages or losses), even if such Contributor
- *      has been advised of the possibility of such damages.
- *
- *   9. Accepting Warranty or Additional Liability. While redistributing
- *      the Work or Derivative Works thereof, You may choose to offer,
- *      and charge a fee for, acceptance of support, warranty, indemnity,
- *      or other liability obligations and/or rights consistent with this
- *      License. However, in accepting such obligations, You may act only
- *      on Your own behalf and on Your sole responsibility, not on behalf
- *      of any other Contributor, and only if You agree to indemnify,
- *      defend, and hold each Contributor harmless for any liability
- *      incurred by, or claims asserted against, such Contributor by reason
- *      of your accepting any such warranty or additional liability.
- *
- *   END OF TERMS AND CONDITIONS
- *
- *   APPENDIX: How to apply the Apache License to your work.
- *
- *      To apply the Apache License to your work, attach the following
- *      boilerplate notice, with the fields enclosed by brackets "[]"
- *      replaced with your own identifying information. (Don't include
- *      the brackets!)  The text should be enclosed in the appropriate
- *      comment syntax for the file format. We also recommend that a
- *      file or class name and description of purpose be included on the
- *      same "printed page" as the copyright notice for easier
- *      identification within third-party archives.
- *
- *   Copyright [yyyy] [name of copyright owner]
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
+/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 
 /*
  * $Id: LdifComposerImpl.java,v 1.4 2003/07/31 22:01:52 akarasulu Exp $
@@ -221,10 +221,8 @@
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.commons.collections.MultiMap;
-
 import org.apache.ldap.common.util.Base64;
-
+import org.apache.ldap.common.util.MultiMap;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java	Sat Sep 25 12:11:47 2004
@@ -1,218 +1,18 @@
-/*
- *                                 Apache License
- *                           Version 2.0, January 2004
- *                        http://www.apache.org/licenses/
- *
- *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- *
- *   1. Definitions.
- *
- *      "License" shall mean the terms and conditions for use, reproduction,
- *      and distribution as defined by Sections 1 through 9 of this document.
- *
- *      "Licensor" shall mean the copyright owner or entity authorized by
- *      the copyright owner that is granting the License.
- *
- *      "Legal Entity" shall mean the union of the acting entity and all
- *      other entities that control, are controlled by, or are under common
- *      control with that entity. For the purposes of this definition,
- *      "control" means (i) the power, direct or indirect, to cause the
- *      direction or management of such entity, whether by contract or
- *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
- *      outstanding shares, or (iii) beneficial ownership of such entity.
- *
- *      "You" (or "Your") shall mean an individual or Legal Entity
- *      exercising permissions granted by this License.
- *
- *      "Source" form shall mean the preferred form for making modifications,
- *      including but not limited to software source code, documentation
- *      source, and configuration files.
- *
- *      "Object" form shall mean any form resulting from mechanical
- *      transformation or translation of a Source form, including but
- *      not limited to compiled object code, generated documentation,
- *      and conversions to other media types.
- *
- *      "Work" shall mean the work of authorship, whether in Source or
- *      Object form, made available under the License, as indicated by a
- *      copyright notice that is included in or attached to the work
- *      (an example is provided in the Appendix below).
- *
- *      "Derivative Works" shall mean any work, whether in Source or Object
- *      form, that is based on (or derived from) the Work and for which the
- *      editorial revisions, annotations, elaborations, or other modifications
- *      represent, as a whole, an original work of authorship. For the purposes
- *      of this License, Derivative Works shall not include works that remain
- *      separable from, or merely link (or bind by name) to the interfaces of,
- *      the Work and Derivative Works thereof.
- *
- *      "Contribution" shall mean any work of authorship, including
- *      the original version of the Work and any modifications or additions
- *      to that Work or Derivative Works thereof, that is intentionally
- *      submitted to Licensor for inclusion in the Work by the copyright owner
- *      or by an individual or Legal Entity authorized to submit on behalf of
- *      the copyright owner. For the purposes of this definition, "submitted"
- *      means any form of electronic, verbal, or written communication sent
- *      to the Licensor or its representatives, including but not limited to
- *      communication on electronic mailing lists, source code control systems,
- *      and issue tracking systems that are managed by, or on behalf of, the
- *      Licensor for the purpose of discussing and improving the Work, but
- *      excluding communication that is conspicuously marked or otherwise
- *      designated in writing by the copyright owner as "Not a Contribution."
- *
- *      "Contributor" shall mean Licensor and any individual or Legal Entity
- *      on behalf of whom a Contribution has been received by Licensor and
- *      subsequently incorporated within the Work.
- *
- *   2. Grant of Copyright License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      copyright license to reproduce, prepare Derivative Works of,
- *      publicly display, publicly perform, sublicense, and distribute the
- *      Work and such Derivative Works in Source or Object form.
- *
- *   3. Grant of Patent License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      (except as stated in this section) patent license to make, have made,
- *      use, offer to sell, sell, import, and otherwise transfer the Work,
- *      where such license applies only to those patent claims licensable
- *      by such Contributor that are necessarily infringed by their
- *      Contribution(s) alone or by combination of their Contribution(s)
- *      with the Work to which such Contribution(s) was submitted. If You
- *      institute patent litigation against any entity (including a
- *      cross-claim or counterclaim in a lawsuit) alleging that the Work
- *      or a Contribution incorporated within the Work constitutes direct
- *      or contributory patent infringement, then any patent licenses
- *      granted to You under this License for that Work shall terminate
- *      as of the date such litigation is filed.
- *
- *   4. Redistribution. You may reproduce and distribute copies of the
- *      Work or Derivative Works thereof in any medium, with or without
- *      modifications, and in Source or Object form, provided that You
- *      meet the following conditions:
- *
- *      (a) You must give any other recipients of the Work or
- *          Derivative Works a copy of this License; and
- *
- *      (b) You must cause any modified files to carry prominent notices
- *          stating that You changed the files; and
- *
- *      (c) You must retain, in the Source form of any Derivative Works
- *          that You distribute, all copyright, patent, trademark, and
- *          attribution notices from the Source form of the Work,
- *          excluding those notices that do not pertain to any part of
- *          the Derivative Works; and
- *
- *      (d) If the Work includes a "NOTICE" text file as part of its
- *          distribution, then any Derivative Works that You distribute must
- *          include a readable copy of the attribution notices contained
- *          within such NOTICE file, excluding those notices that do not
- *          pertain to any part of the Derivative Works, in at least one
- *          of the following places: within a NOTICE text file distributed
- *          as part of the Derivative Works; within the Source form or
- *          documentation, if provided along with the Derivative Works; or,
- *          within a display generated by the Derivative Works, if and
- *          wherever such third-party notices normally appear. The contents
- *          of the NOTICE file are for informational purposes only and
- *          do not modify the License. You may add Your own attribution
- *          notices within Derivative Works that You distribute, alongside
- *          or as an addendum to the NOTICE text from the Work, provided
- *          that such additional attribution notices cannot be construed
- *          as modifying the License.
- *
- *      You may add Your own copyright statement to Your modifications and
- *      may provide additional or different license terms and conditions
- *      for use, reproduction, or distribution of Your modifications, or
- *      for any such Derivative Works as a whole, provided Your use,
- *      reproduction, and distribution of the Work otherwise complies with
- *      the conditions stated in this License.
- *
- *   5. Submission of Contributions. Unless You explicitly state otherwise,
- *      any Contribution intentionally submitted for inclusion in the Work
- *      by You to the Licensor shall be under the terms and conditions of
- *      this License, without any additional terms or conditions.
- *      Notwithstanding the above, nothing herein shall supersede or modify
- *      the terms of any separate license agreement you may have executed
- *      with Licensor regarding such Contributions.
- *
- *   6. Trademarks. This License does not grant permission to use the trade
- *      names, trademarks, service marks, or product names of the Licensor,
- *      except as required for reasonable and customary use in describing the
- *      origin of the Work and reproducing the content of the NOTICE file.
- *
- *   7. Disclaimer of Warranty. Unless required by applicable law or
- *      agreed to in writing, Licensor provides the Work (and each
- *      Contributor provides its Contributions) on an "AS IS" BASIS,
- *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- *      implied, including, without limitation, any warranties or conditions
- *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- *      PARTICULAR PURPOSE. You are solely responsible for determining the
- *      appropriateness of using or redistributing the Work and assume any
- *      risks associated with Your exercise of permissions under this License.
- *
- *   8. Limitation of Liability. In no event and under no legal theory,
- *      whether in tort (including negligence), contract, or otherwise,
- *      unless required by applicable law (such as deliberate and grossly
- *      negligent acts) or agreed to in writing, shall any Contributor be
- *      liable to You for damages, including any direct, indirect, special,
- *      incidental, or consequential damages of any character arising as a
- *      result of this License or out of the use or inability to use the
- *      Work (including but not limited to damages for loss of goodwill,
- *      work stoppage, computer failure or malfunction, or any and all
- *      other commercial damages or losses), even if such Contributor
- *      has been advised of the possibility of such damages.
- *
- *   9. Accepting Warranty or Additional Liability. While redistributing
- *      the Work or Derivative Works thereof, You may choose to offer,
- *      and charge a fee for, acceptance of support, warranty, indemnity,
- *      or other liability obligations and/or rights consistent with this
- *      License. However, in accepting such obligations, You may act only
- *      on Your own behalf and on Your sole responsibility, not on behalf
- *      of any other Contributor, and only if You agree to indemnify,
- *      defend, and hold each Contributor harmless for any liability
- *      incurred by, or claims asserted against, such Contributor by reason
- *      of your accepting any such warranty or additional liability.
- *
- *   END OF TERMS AND CONDITIONS
- *
- *   APPENDIX: How to apply the Apache License to your work.
- *
- *      To apply the Apache License to your work, attach the following
- *      boilerplate notice, with the fields enclosed by brackets "[]"
- *      replaced with your own identifying information. (Don't include
- *      the brackets!)  The text should be enclosed in the appropriate
- *      comment syntax for the file format. We also recommend that a
- *      file or class name and description of purpose be included on the
- *      same "printed page" as the copyright notice for easier
- *      identification within third-party archives.
- *
- *   Copyright [yyyy] [name of copyright owner]
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
-
 /*
- * $Id: LdifParser.java,v 1.7 2003/07/31 21:44:49 akarasulu Exp $
- * $Prologue$
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * -- (c) LDAPd Group                                                    --
- * -- Please refer to the LICENSE.txt file in the root directory of      --
- * -- any LDAPd project for copyright and distribution information.      --
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
-
 package org.apache.ldap.common.ldif ;
 
 
@@ -221,7 +21,7 @@
 import javax.naming.NamingException ;
 import javax.naming.directory.Attributes ;
 
-import org.apache.commons.collections.MultiMap ;
+import org.apache.ldap.common.util.MultiMap;
 
 
 

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java	Sat Sep 25 12:11:47 2004
@@ -1,215 +1,17 @@
-/*
- *                                 Apache License
- *                           Version 2.0, January 2004
- *                        http://www.apache.org/licenses/
- *
- *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
- *
- *   1. Definitions.
- *
- *      "License" shall mean the terms and conditions for use, reproduction,
- *      and distribution as defined by Sections 1 through 9 of this document.
- *
- *      "Licensor" shall mean the copyright owner or entity authorized by
- *      the copyright owner that is granting the License.
- *
- *      "Legal Entity" shall mean the union of the acting entity and all
- *      other entities that control, are controlled by, or are under common
- *      control with that entity. For the purposes of this definition,
- *      "control" means (i) the power, direct or indirect, to cause the
- *      direction or management of such entity, whether by contract or
- *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
- *      outstanding shares, or (iii) beneficial ownership of such entity.
- *
- *      "You" (or "Your") shall mean an individual or Legal Entity
- *      exercising permissions granted by this License.
- *
- *      "Source" form shall mean the preferred form for making modifications,
- *      including but not limited to software source code, documentation
- *      source, and configuration files.
- *
- *      "Object" form shall mean any form resulting from mechanical
- *      transformation or translation of a Source form, including but
- *      not limited to compiled object code, generated documentation,
- *      and conversions to other media types.
- *
- *      "Work" shall mean the work of authorship, whether in Source or
- *      Object form, made available under the License, as indicated by a
- *      copyright notice that is included in or attached to the work
- *      (an example is provided in the Appendix below).
- *
- *      "Derivative Works" shall mean any work, whether in Source or Object
- *      form, that is based on (or derived from) the Work and for which the
- *      editorial revisions, annotations, elaborations, or other modifications
- *      represent, as a whole, an original work of authorship. For the purposes
- *      of this License, Derivative Works shall not include works that remain
- *      separable from, or merely link (or bind by name) to the interfaces of,
- *      the Work and Derivative Works thereof.
- *
- *      "Contribution" shall mean any work of authorship, including
- *      the original version of the Work and any modifications or additions
- *      to that Work or Derivative Works thereof, that is intentionally
- *      submitted to Licensor for inclusion in the Work by the copyright owner
- *      or by an individual or Legal Entity authorized to submit on behalf of
- *      the copyright owner. For the purposes of this definition, "submitted"
- *      means any form of electronic, verbal, or written communication sent
- *      to the Licensor or its representatives, including but not limited to
- *      communication on electronic mailing lists, source code control systems,
- *      and issue tracking systems that are managed by, or on behalf of, the
- *      Licensor for the purpose of discussing and improving the Work, but
- *      excluding communication that is conspicuously marked or otherwise
- *      designated in writing by the copyright owner as "Not a Contribution."
- *
- *      "Contributor" shall mean Licensor and any individual or Legal Entity
- *      on behalf of whom a Contribution has been received by Licensor and
- *      subsequently incorporated within the Work.
- *
- *   2. Grant of Copyright License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      copyright license to reproduce, prepare Derivative Works of,
- *      publicly display, publicly perform, sublicense, and distribute the
- *      Work and such Derivative Works in Source or Object form.
- *
- *   3. Grant of Patent License. Subject to the terms and conditions of
- *      this License, each Contributor hereby grants to You a perpetual,
- *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- *      (except as stated in this section) patent license to make, have made,
- *      use, offer to sell, sell, import, and otherwise transfer the Work,
- *      where such license applies only to those patent claims licensable
- *      by such Contributor that are necessarily infringed by their
- *      Contribution(s) alone or by combination of their Contribution(s)
- *      with the Work to which such Contribution(s) was submitted. If You
- *      institute patent litigation against any entity (including a
- *      cross-claim or counterclaim in a lawsuit) alleging that the Work
- *      or a Contribution incorporated within the Work constitutes direct
- *      or contributory patent infringement, then any patent licenses
- *      granted to You under this License for that Work shall terminate
- *      as of the date such litigation is filed.
- *
- *   4. Redistribution. You may reproduce and distribute copies of the
- *      Work or Derivative Works thereof in any medium, with or without
- *      modifications, and in Source or Object form, provided that You
- *      meet the following conditions:
- *
- *      (a) You must give any other recipients of the Work or
- *          Derivative Works a copy of this License; and
- *
- *      (b) You must cause any modified files to carry prominent notices
- *          stating that You changed the files; and
- *
- *      (c) You must retain, in the Source form of any Derivative Works
- *          that You distribute, all copyright, patent, trademark, and
- *          attribution notices from the Source form of the Work,
- *          excluding those notices that do not pertain to any part of
- *          the Derivative Works; and
- *
- *      (d) If the Work includes a "NOTICE" text file as part of its
- *          distribution, then any Derivative Works that You distribute must
- *          include a readable copy of the attribution notices contained
- *          within such NOTICE file, excluding those notices that do not
- *          pertain to any part of the Derivative Works, in at least one
- *          of the following places: within a NOTICE text file distributed
- *          as part of the Derivative Works; within the Source form or
- *          documentation, if provided along with the Derivative Works; or,
- *          within a display generated by the Derivative Works, if and
- *          wherever such third-party notices normally appear. The contents
- *          of the NOTICE file are for informational purposes only and
- *          do not modify the License. You may add Your own attribution
- *          notices within Derivative Works that You distribute, alongside
- *          or as an addendum to the NOTICE text from the Work, provided
- *          that such additional attribution notices cannot be construed
- *          as modifying the License.
- *
- *      You may add Your own copyright statement to Your modifications and
- *      may provide additional or different license terms and conditions
- *      for use, reproduction, or distribution of Your modifications, or
- *      for any such Derivative Works as a whole, provided Your use,
- *      reproduction, and distribution of the Work otherwise complies with
- *      the conditions stated in this License.
- *
- *   5. Submission of Contributions. Unless You explicitly state otherwise,
- *      any Contribution intentionally submitted for inclusion in the Work
- *      by You to the Licensor shall be under the terms and conditions of
- *      this License, without any additional terms or conditions.
- *      Notwithstanding the above, nothing herein shall supersede or modify
- *      the terms of any separate license agreement you may have executed
- *      with Licensor regarding such Contributions.
- *
- *   6. Trademarks. This License does not grant permission to use the trade
- *      names, trademarks, service marks, or product names of the Licensor,
- *      except as required for reasonable and customary use in describing the
- *      origin of the Work and reproducing the content of the NOTICE file.
- *
- *   7. Disclaimer of Warranty. Unless required by applicable law or
- *      agreed to in writing, Licensor provides the Work (and each
- *      Contributor provides its Contributions) on an "AS IS" BASIS,
- *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- *      implied, including, without limitation, any warranties or conditions
- *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- *      PARTICULAR PURPOSE. You are solely responsible for determining the
- *      appropriateness of using or redistributing the Work and assume any
- *      risks associated with Your exercise of permissions under this License.
- *
- *   8. Limitation of Liability. In no event and under no legal theory,
- *      whether in tort (including negligence), contract, or otherwise,
- *      unless required by applicable law (such as deliberate and grossly
- *      negligent acts) or agreed to in writing, shall any Contributor be
- *      liable to You for damages, including any direct, indirect, special,
- *      incidental, or consequential damages of any character arising as a
- *      result of this License or out of the use or inability to use the
- *      Work (including but not limited to damages for loss of goodwill,
- *      work stoppage, computer failure or malfunction, or any and all
- *      other commercial damages or losses), even if such Contributor
- *      has been advised of the possibility of such damages.
- *
- *   9. Accepting Warranty or Additional Liability. While redistributing
- *      the Work or Derivative Works thereof, You may choose to offer,
- *      and charge a fee for, acceptance of support, warranty, indemnity,
- *      or other liability obligations and/or rights consistent with this
- *      License. However, in accepting such obligations, You may act only
- *      on Your own behalf and on Your sole responsibility, not on behalf
- *      of any other Contributor, and only if You agree to indemnify,
- *      defend, and hold each Contributor harmless for any liability
- *      incurred by, or claims asserted against, such Contributor by reason
- *      of your accepting any such warranty or additional liability.
- *
- *   END OF TERMS AND CONDITIONS
- *
- *   APPENDIX: How to apply the Apache License to your work.
- *
- *      To apply the Apache License to your work, attach the following
- *      boilerplate notice, with the fields enclosed by brackets "[]"
- *      replaced with your own identifying information. (Don't include
- *      the brackets!)  The text should be enclosed in the appropriate
- *      comment syntax for the file format. We also recommend that a
- *      file or class name and description of purpose be included on the
- *      same "printed page" as the copyright notice for easier
- *      identification within third-party archives.
- *
- *   Copyright [yyyy] [name of copyright owner]
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
-
 /*
- * $id$
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * -- (c) LDAPd Group                                                    --
- * -- Please refer to the LICENSE.txt file in the root directory of      --
- * -- any LDAPd project for copyright and distribution information.      --
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 package org.apache.ldap.common.ldif ;
 
@@ -224,9 +26,8 @@
 import javax.naming.directory.Attributes ;
 import javax.naming.directory.DirContext ;
 
-import org.apache.commons.collections.MultiMap ;
-
 import org.apache.ldap.common.util.Base64 ;
+import org.apache.ldap.common.util.MultiMap;
 
 
 /**
@@ -446,7 +247,6 @@
         String l_line ;
         String l_attrName = new String () ;
         String l_attrValue = new String () ;
-        String l_prevAttrName = null ;
         String l_prevAttrValue = null ;
         StringReader l_strIn = new StringReader( an_ldif ) ;
         BufferedReader l_in = new BufferedReader( l_strIn ) ;
@@ -465,7 +265,8 @@
                         {
                             if ( l_currentModOp == -1 )
                             {
-                                throw new ParseException( "A modification"
                                    + " type must be supplied for a change "
+                                throw new ParseException( "A modification"
+                                    + " type must be supplied for a change "
                                     + "type of modify", l_lineCount ) ;
                             }
                             l_entry.addModificationItem( l_currentModOp, 
@@ -487,7 +288,6 @@
                     }
                     l_currentModOp = -1 ;
                     l_prevAttrValue = null ;
-                    l_prevAttrName = null ;
                     continue ;
                 }
                 // Try to advance to ':' if one exists.
@@ -579,7 +379,6 @@
                     l_currentModOp = DirContext.REMOVE_ATTRIBUTE ;
                     if ( l_attrValue != null )
                     {
-                        l_prevAttrName = l_attrName ;
                         l_prevAttrValue = l_attrValue ;
                     } 
                 }

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindRequestImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindRequestImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindRequestImpl.java	Sat Sep 25 12:11:47 2004
@@ -16,7 +16,8 @@
  */
 package org.apache.ldap.common.message;
 
-import org.apache.commons.lang.ArrayUtils;
+
+import org.apache.ldap.common.util.ArrayUtils;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindResponseImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindResponseImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/BindResponseImpl.java	Sat Sep 25 12:11:47 2004
@@ -16,7 +16,8 @@
  */
 package org.apache.ldap.common.message;
 
-import org.apache.commons.lang.ArrayUtils;
+
+import org.apache.ldap.common.util.ArrayUtils;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/DerefAliasesEnum.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/DerefAliasesEnum.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/DerefAliasesEnum.java	Sat Sep 25 12:11:47 2004
@@ -1,27 +1,27 @@
-/*
- *   Copyright 2004 The Apache Software Foundation
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.ldap.common.message ;
 
 
-import java.util.Hashtable ;
-
-import org.apache.commons.lang.enum.ValuedEnum ;
+import java.util.Hashtable ;
+
+import org.apache.ldap.common.util.ValuedEnum;
+
 
-
 /**
  * Type-safe derefAliases search parameter enumeration which determines the mode
  * of alias handling.  Note that the names of these ValuedEnums correspond to 

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedRequestImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedRequestImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedRequestImpl.java	Sat Sep 25 12:11:47 2004
@@ -16,7 +16,8 @@
  */
 package org.apache.ldap.common.message;
 
-import org.apache.commons.lang.ArrayUtils;
+
+import org.apache.ldap.common.util.ArrayUtils;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedResponseImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedResponseImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ExtendedResponseImpl.java	Sat Sep 25 12:11:47 2004
@@ -16,7 +16,8 @@
  */
 package org.apache.ldap.common.message ;
 
-import org.apache.commons.lang.ArrayUtils;
+
+import org.apache.ldap.common.util.ArrayUtils;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/LockableAttributesImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/LockableAttributesImpl.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/LockableAttributesImpl.java	Sat Sep 25 12:11:47 2004
@@ -26,7 +26,7 @@
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 
-import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.ldap.common.util.ExceptionUtils;
 
 import org.apache.ldap.common.Lockable;
 import org.apache.ldap.common.AbstractLockable;

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/MessageTypeEnum.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/MessageTypeEnum.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/MessageTypeEnum.java	Sat Sep 25 12:11:47 2004
@@ -1,23 +1,23 @@
-/*
- *   Copyright 2004 The Apache Software Foundation
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.ldap.common.message ;
-
-
-import org.apache.commons.lang.enum.ValuedEnum ;
+
+
+import org.apache.ldap.common.util.ValuedEnum ;
 
 
 /**

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ResultCodeEnum.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ResultCodeEnum.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ResultCodeEnum.java	Sat Sep 25 12:11:47 2004
@@ -1,23 +1,23 @@
-/*
- *   Copyright 2004 The Apache Software Foundation
- *
- *   Licensed under the Apache License, Version 2.0 (the "License");
- *   you may not use this file except in compliance with the License.
- *   You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing, software
- *   distributed under the License is distributed on an "AS IS" BASIS,
- *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *   See the License for the specific language governing permissions and
- *   limitations under the License.
- *
- */
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.ldap.common.message ;
 
 
-import org.apache.commons.lang.enum.ValuedEnum ; 
+import org.apache.ldap.common.util.ValuedEnum ; 
 
 
 /**
@@ -918,9 +918,9 @@
     private ResultCodeEnum( final String a_name, final int a_value )
     {
         super( a_name, a_value ) ;
-    }
-    
-    
+    }
+    
+    
     /**
      * Gets the set of general error codes.
      *

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ScopeEnum.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ScopeEnum.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/message/ScopeEnum.java	Sat Sep 25 12:11:47 2004
@@ -19,6 +19,8 @@
 
 import javax.naming.directory.SearchControls ;
 
+import org.apache.ldap.common.util.ValuedEnum;
+
 
 /**
  * Type-safe scope parameter enumeration.
@@ -28,7 +30,7 @@
  * @version $Revision: 1.4 $
  */
 public class ScopeEnum
-    extends org.apache.commons.lang.enum.ValuedEnum
+    extends ValuedEnum
 {
     /** Search scope parameter value for base object search */
     public static final int BASEOBJECT_VAL = SearchControls.OBJECT_SCOPE ;

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/name/DnParser.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/name/DnParser.java	(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/name/DnParser.java	Sat Sep 25 12:11:47 2004
@@ -26,8 +26,8 @@
 import javax.naming.NamingException ;
 import javax.naming.InvalidNameException ;
 
-import org.apache.commons.lang.exception.ExceptionUtils ;
-import org.apache.commons.lang.exception.NestableRuntimeException ;
+import org.apache.ldap.common.util.ExceptionUtils ;
+import org.apache.ldap.common.util.NestableRuntimeException ;
 
 import antlr.TokenStreamSelector ;
 import antlr.RecognitionException ;

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ArrayUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ArrayUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,3838 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * <p>Operations on arrays, primitive arrays (like <code>int[]</code>) and
+ * primitive wrapper arrays (like <code>Integer[]</code>).</p>
+ * 
+ * <p>This class tries to handle <code>null</code> input gracefully.
+ * An exception will not be thrown for a <code>null</code>
+ * array input. However, an Object array that contains a <code>null</code>
+ * element may throw an exception. Each method documents its behaviour.</p>
+ *
+ * @author Stephen Colebourne
+ * @author Moritz Petersen
+ * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
+ * @author Nikolay Metchev
+ * @author Matthew Hawthorne
+ * @author Tim O'Brien
+ * @author Pete Gieser
+ * @author Gary Gregory
+ * @author <a href="mailto:equinus100@hotmail.com">Ashwin S</a>
+ * @author Maarten Coene
+ * @since 2.0
+ * @version $Id: ArrayUtils.java,v 1.46 2004/08/15 02:12:51 bayard Exp $
+ */
+public class ArrayUtils {
+
+    /**
+     * An empty immutable <code>Object</code> array.
+     */
+    public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+    /**
+     * An empty immutable <code>Class</code> array.
+     */
+    public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+    /**
+     * An empty immutable <code>String</code> array.
+     */
+    public static final String[] EMPTY_STRING_ARRAY = new String[0];
+    /**
+     * An empty immutable <code>long</code> array.
+     */
+    public static final long[] EMPTY_LONG_ARRAY = new long[0];
+    /**
+     * An empty immutable <code>Long</code> array.
+     */
+    public static final Long[] EMPTY_LONG_OBJECT_ARRAY = new Long[0];
+    /**
+     * An empty immutable <code>int</code> array.
+     */
+    public static final int[] EMPTY_INT_ARRAY = new int[0];
+    /**
+     * An empty immutable <code>Integer</code> array.
+     */
+    public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0];
+    /**
+     * An empty immutable <code>short</code> array.
+     */
+    public static final short[] EMPTY_SHORT_ARRAY = new short[0];
+    /**
+     * An empty immutable <code>Short</code> array.
+     */
+    public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = new Short[0];
+    /**
+     * An empty immutable <code>byte</code> array.
+     */
+    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    /**
+     * An empty immutable <code>Byte</code> array.
+     */
+    public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = new Byte[0];
+    /**
+     * An empty immutable <code>double</code> array.
+     */
+    public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+    /**
+     * An empty immutable <code>Double</code> array.
+     */
+    public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = new Double[0];
+    /**
+     * An empty immutable <code>float</code> array.
+     */
+    public static final float[] EMPTY_FLOAT_ARRAY = new float[0];
+    /**
+     * An empty immutable <code>Float</code> array.
+     */
+    public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = new Float[0];
+    /**
+     * An empty immutable <code>boolean</code> array.
+     */
+    public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
+    /**
+     * An empty immutable <code>Boolean</code> array.
+     */
+    public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = new Boolean[0];
+    /**
+     * An empty immutable <code>char</code> array.
+     */
+    public static final char[] EMPTY_CHAR_ARRAY = new char[0];
+    /**
+     * An empty immutable <code>Character</code> array.
+     */
+    public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = new Character[0];
+
+    /**
+     * <p>ArrayUtils instances should NOT be constructed in standard programming.
+     * Instead, the class should be used as <code>ArrayUtils.clone(new int[] {2})</code>.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean instance
+     * to operate.</p>
+     */
+    public ArrayUtils() {
+    }
+    
+    // Basic methods handling multi-dimensional arrays
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Outputs an array as a String, treating <code>null</code> as an empty array.</p>
+     *
+     * <p>Multi-dimensional arrays are handled correctly, including
+     * multi-dimensional primitive arrays.</p>
+     *
+     * <p>The format is that of Java source code, for example <code>{a,b}</code>.</p>
+     * 
+     * @param array  the array to get a toString for, may be <code>null</code>
+     * @return a String representation of the array, '{}' if null array input
+     */
+    public static String toString(Object array) {
+        return toString(array, "{}");
+    }
+
+    /**
+     * <p>Outputs an array as a String handling <code>null</code>s.</p>
+     *
+     * <p>Multi-dimensional arrays are handled correctly, including
+     * multi-dimensional primitive arrays.</p>
+     *
+     * <p>The format is that of Java source code, for example <code>{a,b}</code>.</p>
+     * 
+     * @param array  the array to get a toString for, may be <code>null</code>
+     * @param stringIfNull  the String to return if the array is <code>null</code>
+     * @return a String representation of the array
+     */    
+    public static String toString(Object array, String stringIfNull) {
+        if (array == null) {
+            return stringIfNull;
+        }
+        return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
+    }
+
+    /**
+     * <p>Get a hashCode for an array handling multi-dimensional arrays correctly.</p>
+     * 
+     * <p>Multi-dimensional primitive arrays are also handled correctly by this method.</p>
+     * 
+     * @param array  the array to get a hashCode for, may be <code>null</code>
+     * @return a hashCode for the array, zero if null array input
+     */
+    public static int hashCode(Object array) {
+        return new HashCodeBuilder().append(array).toHashCode();
+    }
+
+    /**
+     * <p>Compares two arrays, using equals(), handling multi-dimensional arrays
+     * correctly.</p>
+     * 
+     * <p>Multi-dimensional primitive arrays are also handled correctly by this method.</p>
+     * 
+     * @param array1  the left hand array to compare, may be <code>null</code>
+     * @param array2  the right hand array to compare, may be <code>null</code>
+     * @return <code>true</code> if the arrays are equal
+     */
+    public static boolean isEquals(Object array1, Object array2) {
+        return new EqualsBuilder().append(array1, array2).isEquals();
+    }
+
+    // To map
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts the given array into a {@link java.util.Map}. Each element of the array
+     * must be either a {@link java.util.Map.Entry} or an Array, containing at least two
+     * elements, where the first element is used as key and the second as
+     * value.</p>
+     *
+     * <p>This method can be used to initialize:</p>
+     * <pre>
+     * // Create a Map mapping colors.
+     * Map colorMap = MapUtils.toMap(new String[][] {{
+     *     {"RED", "#FF0000"},
+     *     {"GREEN", "#00FF00"},
+     *     {"BLUE", "#0000FF"}});
+     * </pre>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     *
+     * @param array  an array whose elements are either a {@link java.util.Map.Entry} or
+     *  an Array containing at least two elements, may be <code>null</code>
+     * @return a <code>Map</code> that was created from the array
+     * @throws IllegalArgumentException  if one element of this Array is
+     *  itself an Array containing less then two elements
+     * @throws IllegalArgumentException  if the array contains elements other
+     *  than {@link java.util.Map.Entry} and an Array
+     */
+    public static Map toMap(Object[] array) {
+        if (array == null) {
+            return null;
+        }
+        final Map map = new HashMap((int) (array.length * 1.5));
+        for (int i = 0; i < array.length; i++) {
+            Object object = array[i];
+            if (object instanceof Map.Entry) {
+                Map.Entry entry = (Map.Entry) object;
+                map.put(entry.getKey(), entry.getValue());
+            } else if (object instanceof Object[]) {
+                Object[] entry = (Object[]) object;
+                if (entry.length < 2) {
+                    throw new IllegalArgumentException("Array element " + i + ", '"
+                        + object
+                        + "', has a length less than 2");
+                }
+                map.put(entry[0], entry[1]);
+            } else {
+                throw new IllegalArgumentException("Array element " + i + ", '"
+                        + object
+                        + "', is neither of type Map.Entry nor an Array");
+            }
+        }
+        return map;
+    }
+
+    // Clone
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Shallow clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>The objects in the array are not cloned, thus there is no special
+     * handling for multi-dimensional arrays.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to shallow clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static Object[] clone(Object[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (Object[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static long[] clone(long[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (long[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static int[] clone(int[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (int[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static short[] clone(short[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (short[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static char[] clone(char[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (char[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static byte[] clone(byte[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (byte[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static double[] clone(double[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (double[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static float[] clone(float[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (float[]) array.clone();
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * <code>null</code>.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to clone, may be <code>null</code>
+     * @return the cloned array, <code>null</code> if <code>null</code> input
+     */
+    public static boolean[] clone(boolean[] array) {
+        if (array == null) {
+            return null;
+        }
+        return (boolean[]) array.clone();
+    }
+
+    // Subarrays
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Produces a new array containing the elements between
+     * the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * <p>The component type of the subarray is always the same as
+     * that of the input array. Thus, if the input is an array of type
+     * <code>Date</code>, the following usage is envisaged:</p>
+     *
+     * <pre>
+     * Date[] someDates = (Date[])ArrayUtils.subarray(allDates, 2, 5);
+     * </pre>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static Object[] subarray(Object[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        Class type = array.getClass().getComponentType();
+        if (newSize <= 0) {
+            return (Object[]) Array.newInstance(type, 0);
+        }
+        Object[] subarray = (Object[]) Array.newInstance(type, newSize);
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>long</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static long[] subarray(long[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_LONG_ARRAY;
+        }
+
+        long[] subarray = new long[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>int</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static int[] subarray(int[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_INT_ARRAY;
+        }
+
+        int[] subarray = new int[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>short</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static short[] subarray(short[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_SHORT_ARRAY;
+        }
+
+        short[] subarray = new short[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>char</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static char[] subarray(char[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_CHAR_ARRAY;
+        }
+
+        char[] subarray = new char[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>byte</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+
+        byte[] subarray = new byte[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>double</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static double[] subarray(double[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_DOUBLE_ARRAY;
+        }
+
+        double[] subarray = new double[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>float</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static float[] subarray(float[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_FLOAT_ARRAY;
+        }
+
+        float[] subarray = new float[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Produces a new <code>boolean</code> array containing the elements
+     * between the start and end indices.</p>
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.</p>
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     */
+    public static boolean[] subarray(boolean[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_BOOLEAN_ARRAY;
+        }
+
+        boolean[] subarray = new boolean[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    // Is same length
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.
+     *
+     * <p>Any multi-dimensional aspects of the arrays are ignored.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */    
+    public static boolean isSameLength(Object[] array1, Object[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(long[] array1, long[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(int[] array1, int[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(short[] array1, short[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(char[] array1, char[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(byte[] array1, byte[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(double[] array1, double[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(float[] array1, float[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>Checks whether two arrays are the same length, treating
+     * <code>null</code> arrays as length <code>0</code>.</p>
+     * 
+     * @param array1 the first array, may be <code>null</code>
+     * @param array2 the second array, may be <code>null</code>
+     * @return <code>true</code> if length of arrays matches, treating
+     *  <code>null</code> as an empty array
+     */
+    public static boolean isSameLength(boolean[] array1, boolean[] array2) {
+        if ((array1 == null && array2 != null && array2.length > 0) ||
+            (array2 == null && array1 != null && array1.length > 0) ||
+            (array1 != null && array2 != null && array1.length != array2.length)) {
+                return false;
+        }
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Returns the length of the specified array.
+     * This method can deal with <code>Object</code> arrays and with primitive arrays.</p>
+     *
+     * <p>If the input array is <code>null</code>, <code>0</code> is returned.</p>
+     *
+     * <pre>
+     * ArrayUtils.getLength(null)            = 0
+     * ArrayUtils.getLength([])              = 0
+     * ArrayUtils.getLength([null])          = 1
+     * ArrayUtils.getLength([true, false])   = 2
+     * ArrayUtils.getLength([1, 2, 3])       = 3
+     * ArrayUtils.getLength(["a", "b", "c"]) = 3
+     * </pre>
+     *
+     * @param array  the array to retrieve the length from, may be null
+     * @return The length of the array, or <code>0</code> if the array is <code>null</code>
+     * @throws IllegalArgumentException if the object arguement is not an array.
+     */
+    public static int getLength(Object array) {
+        if (array == null) {
+            return 0;
+        } else {
+            return Array.getLength(array);
+        }
+    }
+    
+    /**
+     * Returns the last index of the given array or -1 if empty or null.
+     * This method can deal with <code>Object</code> arrays and with primitive arrays.
+     * This value is one less than the size since arrays indices are 0-based.</p>
+     *
+     * <pre>
+     * ArrayUtils.lastIndex(null)            = -1
+     * ArrayUtils.lastIndex([])              = -1
+     * ArrayUtils.lastIndex([null])          = 0
+     * ArrayUtils.lastIndex([true, false])   = 1
+     * ArrayUtils.lastIndex([1, 2, 3])       = 2
+     * ArrayUtils.lastIndex(["a", "b", "c"]) = 2
+     * </pre>
+     *  
+     * @param array  the array to return the last index for, may be null
+     * @return the last index, -1 if empty or null
+     * @throws IllegalArgumentException if the object arguement is not an array.
+     */
+    public static int lastIndex(Object array) {
+        return ArrayUtils.getLength(array) - 1;
+    }
+    
+    /**
+     * <p>Checks whether two arrays are the same type taking into account
+     * multi-dimensional arrays.</p>
+     * 
+     * @param array1 the first array, must not be <code>null</code>
+     * @param array2 the second array, must not be <code>null</code>
+     * @return <code>true</code> if type of arrays matches
+     * @throws IllegalArgumentException if either array is <code>null</code>
+     */    
+    public static boolean isSameType(Object array1, Object array2) {
+        if (array1 == null || array2 == null) {
+            throw new IllegalArgumentException("The Array must not be null");
+        }
+        return array1.getClass().getName().equals(array2.getClass().getName());
+    }
+
+    // Reverse
+    //-----------------------------------------------------------------------
+    /** 
+     * <p>Reverses the order of the given array.</p>
+     *
+     * <p>There is no special handling for multi-dimensional arrays.</p>
+     *
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(Object[] array) {
+        if (array == null) {
+            return;
+        }
+        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++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(long[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        long tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(int[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        int tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(short[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        short tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(char[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        char tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(byte[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        byte tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(double[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        double tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(float[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        float tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    /**
+     * <p>Reverses the order of the given array.</p>
+     * 
+     * <p>This method does nothing if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to reverse, may be <code>null</code>
+     */
+    public static void reverse(boolean[] array) {
+        if (array == null) {
+            return;
+        }
+        int i = 0;
+        int j = array.length - 1;
+        boolean tmp;
+        while (j > i) {
+            tmp = array[j];
+            array[j] = array[i];
+            array[i] = tmp;
+            j--;
+            i++;
+        }
+    }
+
+    // IndexOf search
+    // ----------------------------------------------------------------------
+    
+    // Object IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given object in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param objectToFind  the object to find, may be <code>null</code>
+     * @return the index of the object within the array, 
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(Object[] array, Object objectToFind) {
+        return indexOf(array, objectToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given object in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return <code>-1</code>.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param objectToFind  the object to find, may be <code>null</code>
+     * @param startIndex  the index to start searching at
+     * @return the index of the object within the array starting at the index,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        if (objectToFind == null) {
+            for (int i = startIndex; i < array.length; i++) {
+                if (array[i] == null) {
+                    return i;
+                }
+            }
+        } else {
+            for (int i = startIndex; i < array.length; i++) {
+                if (objectToFind.equals(array[i])) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given object within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param objectToFind  the object to find, may be <code>null</code>
+     * @return the last index of the object within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(Object[] array, Object objectToFind) {
+        return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given object in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return <code>-1</code>. A startIndex larger than
+     * the array length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param objectToFind  the object to find, may be <code>null</code>
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the object within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(Object[] array, Object objectToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        if (objectToFind == null) {
+            for (int i = startIndex; i >= 0; i--) {
+                if (array[i] == null) {
+                    return i;
+                }
+            }
+        } else {
+            for (int i = startIndex; i >= 0; i--) {
+                if (objectToFind.equals(array[i])) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the object is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param objectToFind  the object to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(Object[] array, Object objectToFind) {
+        return (indexOf(array, objectToFind) != -1);
+    }
+
+    // long IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(long[] array, long valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(long[] array, long valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(long[] array, long valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(long[] array, long valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(long[] array, long valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // int IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(int[] array, int valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(int[] array, int valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(int[] array, int valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(int[] array, int valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(int[] array, int valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // short IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(short[] array, short valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(short[] array, short valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(short[] array, short valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(short[] array, short valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(short[] array, short valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // char IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(char[] array, char valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(char[] array, char valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(char[] array, char valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(char[] array, char valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(char[] array, char valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // byte IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(byte[] array, byte valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(byte[] array, byte valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(byte[] array, byte valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(byte[] array, byte valueToFind, int startIndex) {
+        if (array == null) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(byte[] array, byte valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // double IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(double[] array, double valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value within a given tolerance in the array.
+     * This method will return the index of the first value which falls between the region
+     * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param tolerance tolerance of the search
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(double[] array, double valueToFind, double tolerance) {
+        return indexOf(array, valueToFind, 0, tolerance);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(double[] array, double valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.
+     * This method will return the index of the first value which falls between the region
+     * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @param tolerance tolerance of the search
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        double min = valueToFind - tolerance;
+        double max = valueToFind + tolerance;
+        for (int i = startIndex; i < array.length; i++) {
+            if (array[i] >= min && array[i] <= max) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(double[] array, double valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value within a given tolerance in the array.
+     * This method will return the index of the last value which falls between the region
+     * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param tolerance tolerance of the search
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(double[] array, double valueToFind, double tolerance) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(double[] array, double valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.
+     * This method will return the index of the last value which falls between the region
+     * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @param tolerance  search for value within plus/minus this amount
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        double min = valueToFind - tolerance;
+        double max = valueToFind + tolerance;
+        for (int i = startIndex; i >= 0; i--) {
+            if (array[i] >= min && array[i] <= max) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(double[] array, double valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    /**
+     * <p>Checks if a value falling within the given tolerance is in the
+     * given array.  If the array contains a value within the inclusive range 
+     * defined by (value - tolerance) to (value + tolerance).</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array
+     * is passed in.</p>
+     *
+     * @param array  the array to search
+     * @param valueToFind  the value to find
+     * @param tolerance  the array contains the tolerance of the search
+     * @return true if value falling within tolerance is in array
+     */
+    public static boolean contains(double[] array, double valueToFind, double tolerance) {
+        return (indexOf(array, valueToFind, 0, tolerance) != -1);
+    }
+
+    // float IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(float[] array, float valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(float[] array, float valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(float[] array, float valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(float[] array, float valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(float[] array, float valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // boolean IndexOf
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Find the index of the given value in the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(boolean[] array, boolean valueToFind) {
+        return indexOf(array, valueToFind, 0);
+    }
+
+    /**
+     * <p>Find the index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
+     * length will return -1.</p>
+     * 
+     * @param array  the array to search through for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the index to start searching at
+     * @return the index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int indexOf(boolean[] array, boolean valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        for (int i = startIndex; i < array.length; i++) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the last index of the given value within the array.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  the array to travers backwords looking for the object, may be <code>null</code>
+     * @param valueToFind  the object to find
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(boolean[] array, boolean valueToFind) {
+        return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Find the last index of the given value in the array starting at the given index.</p>
+     *
+     * <p>This method returns <code>-1</code> if <code>null</code> array input.</p>
+     *
+     * <p>A negative startIndex will return -1. A startIndex larger than the array
+     * length will search from the end of the array.</p>
+     * 
+     * @param array  the array to traverse for looking for the object, may be <code>null</code>
+     * @param valueToFind  the value to find
+     * @param startIndex  the start index to travers backwards from
+     * @return the last index of the value within the array,
+     *  <code>-1</code> if not found or <code>null</code> array input
+     */
+    public static int lastIndexOf(boolean[] array, boolean valueToFind, int startIndex) {
+        if (ArrayUtils.isEmpty(array)) {
+            return -1;
+        }
+        if (startIndex < 0) {
+            return -1;
+        } else if (startIndex >= array.length) {
+            startIndex = array.length - 1;
+        }
+        for (int i = startIndex; i >= 0; i--) {
+            if (valueToFind == array[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Checks if the value is in the given array.</p>
+     *
+     * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+     * 
+     * @param array  the array to search through
+     * @param valueToFind  the value to find
+     * @return <code>true</code> if the array contains the object
+     */
+    public static boolean contains(boolean[] array, boolean valueToFind) {
+        return (indexOf(array, valueToFind) != -1);
+    }
+
+    // Primitive/Object array converters
+    // ----------------------------------------------------------------------
+    
+    // Long array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Longs to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Long</code> array, may be <code>null</code>
+     * @return a <code>long</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static long[] toPrimitive(Long[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_LONG_ARRAY;
+        }
+        final long[] result = new long[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].longValue();
+        }
+        return result;
+    }
+    
+    /**
+     * <p>Converts an array of object Long to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Long</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>long</code> array, <code>null</code> if null array input
+     */
+    public static long[] toPrimitive(Long[] array, long valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_LONG_ARRAY;
+        }
+        final long[] result = new long[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Long b = array[i];
+            result[i] = (b == null ? valueForNull : b.longValue());
+        }
+        return result;
+    }
+    
+    /**
+     * <p>Converts an array of primitive longs to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>long</code> array
+     * @return a <code>Long</code> array, <code>null</code> if null array input
+     */
+    public static Long[] toObject(long[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_LONG_OBJECT_ARRAY;
+        }
+        final Long[] result = new Long[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Long(array[i]);
+        }
+        return result;
+    }
+
+    // Int array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Integers to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Integer</code> array, may be <code>null</code>
+     * @return an <code>int</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static int[] toPrimitive(Integer[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_INT_ARRAY;
+        }
+        final int[] result = new int[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].intValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Integer to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Integer</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return an <code>int</code> array, <code>null</code> if null array input
+     */
+    public static int[] toPrimitive(Integer[] array, int valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_INT_ARRAY;
+        }
+        final int[] result = new int[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Integer b = array[i];
+            result[i] = (b == null ? valueForNull : b.intValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive ints to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  an <code>int</code> array
+     * @return an <code>Integer</code> array, <code>null</code> if null array input
+     */
+    public static Integer[] toObject(int[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_INTEGER_OBJECT_ARRAY;
+        }
+        final Integer[] result = new Integer[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Integer(array[i]);
+        }
+        return result;
+    }
+    
+    // Short array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Shorts to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Short</code> array, may be <code>null</code>
+     * @return a <code>byte</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static short[] toPrimitive(Short[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_SHORT_ARRAY;
+        }
+        final short[] result = new short[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].shortValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Short to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Short</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>byte</code> array, <code>null</code> if null array input
+     */
+    public static short[] toPrimitive(Short[] array, short valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_SHORT_ARRAY;
+        }
+        final short[] result = new short[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Short b = array[i];
+            result[i] = (b == null ? valueForNull : b.shortValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive shorts to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>short</code> array
+     * @return a <code>Short</code> array, <code>null</code> if null array input
+     */
+    public static Short[] toObject(short[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_SHORT_OBJECT_ARRAY;
+        }
+        final Short[] result = new Short[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Short(array[i]);
+        }
+        return result;
+    }    
+
+    // Byte array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Bytes to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Byte</code> array, may be <code>null</code>
+     * @return a <code>byte</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static byte[] toPrimitive(Byte[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+        final byte[] result = new byte[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].byteValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Bytes to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Byte</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>byte</code> array, <code>null</code> if null array input
+     */
+    public static byte[] toPrimitive(Byte[] array, byte valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+        final byte[] result = new byte[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Byte b = array[i];
+            result[i] = (b == null ? valueForNull : b.byteValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive bytes to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>byte</code> array
+     * @return a <code>Byte</code> array, <code>null</code> if null array input
+     */
+    public static Byte[] toObject(byte[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BYTE_OBJECT_ARRAY;
+        }
+        final Byte[] result = new Byte[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Byte(array[i]);
+        }
+        return result;
+    }  
+    
+    // Double array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Doubles to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Double</code> array, may be <code>null</code>
+     * @return a <code>double</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static double[] toPrimitive(Double[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_DOUBLE_ARRAY;
+        }
+        final double[] result = new double[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].doubleValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Doubles to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Double</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>double</code> array, <code>null</code> if null array input
+     */
+    public static double[] toPrimitive(Double[] array, double valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_DOUBLE_ARRAY;
+        }
+        final double[] result = new double[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Double b = array[i];
+            result[i] = (b == null ? valueForNull : b.doubleValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive doubles to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>double</code> array
+     * @return a <code>Double</code> array, <code>null</code> if null array input
+     */
+    public static Double[] toObject(double[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_DOUBLE_OBJECT_ARRAY;
+        }
+        final Double[] result = new Double[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Double(array[i]);
+        }
+        return result;
+    }
+
+    //   Float array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Floats to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Float</code> array, may be <code>null</code>
+     * @return a <code>float</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static float[] toPrimitive(Float[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_FLOAT_ARRAY;
+        }
+        final float[] result = new float[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].floatValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Floats to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Float</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>float</code> array, <code>null</code> if null array input
+     */
+    public static float[] toPrimitive(Float[] array, float valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_FLOAT_ARRAY;
+        }
+        final float[] result = new float[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Float b = array[i];
+            result[i] = (b == null ? valueForNull : b.floatValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive floats to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>float</code> array
+     * @return a <code>Float</code> array, <code>null</code> if null array input
+     */
+    public static Float[] toObject(float[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_FLOAT_OBJECT_ARRAY;
+        }
+        final Float[] result = new Float[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = new Float(array[i]);
+        }
+        return result;
+    }
+
+    // Boolean array converters
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Converts an array of object Booleans to primitives.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Boolean</code> array, may be <code>null</code>
+     * @return a <code>boolean</code> array, <code>null</code> if null array input
+     * @throws NullPointerException if array content is <code>null</code>
+     */
+    public static boolean[] toPrimitive(Boolean[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BOOLEAN_ARRAY;
+        }
+        final boolean[] result = new boolean[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = array[i].booleanValue();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of object Booleans to primitives handling <code>null</code>.</p>
+     * 
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>Boolean</code> array, may be <code>null</code>
+     * @param valueForNull  the value to insert if <code>null</code> found
+     * @return a <code>boolean</code> array, <code>null</code> if null array input
+     */
+    public static boolean[] toPrimitive(Boolean[] array, boolean valueForNull) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BOOLEAN_ARRAY;
+        }
+        final boolean[] result = new boolean[array.length];
+        for (int i = 0; i < array.length; i++) {
+            Boolean b = array[i];
+            result[i] = (b == null ? valueForNull : b.booleanValue());
+        }
+        return result;
+    }
+
+    /**
+     * <p>Converts an array of primitive booleans to objects.</p>
+     *
+     * <p>This method returns <code>null</code> if <code>null</code> array input.</p>
+     * 
+     * @param array  a <code>boolean</code> array
+     * @return a <code>Boolean</code> array, <code>null</code> if null array input
+     */
+    public static Boolean[] toObject(boolean[] array) {
+        if (array == null) {
+            return null;
+        } else if (array.length == 0) {
+            return EMPTY_BOOLEAN_OBJECT_ARRAY;
+        }
+        final Boolean[] result = new Boolean[array.length];
+        for (int i = 0; i < array.length; i++) {
+            result[i] = (array[i] ? Boolean.TRUE : Boolean.FALSE);
+        }
+        return result;
+    }
+
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Checks if an array of Objects is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(Object[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive longs is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(long[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive ints is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(int[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive shorts is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(short[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive chars is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(char[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive bytes is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(byte[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive doubles is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(double[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive floats is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(float[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Checks if an array of primitive booleans is empty or <code>null</code>.</p>
+     *
+     * @param array  the array to test
+     * @return <code>true</code> if the array is empty or <code>null</code>
+     * @since 2.1
+     */
+    public static boolean isEmpty(boolean[] array) {
+        if (array == null || array.length == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * <p>Adds all the elements of the given arrays into a new array.</p>
+     * <p>The new array contains all of the element of <code>array1</code> followed
+     * by all of the elements <code>array2</code>. When an array is returned, it is always
+     * a new array.</p>
+     *
+     * <pre>
+     * ArrayUtils.addAll(null, null)     = null
+     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
+     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
+     * ArrayUtils.addAll([], [])         = []
+     * ArrayUtils.addAll([null], [null]) = [null, null]
+     * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
+     * </pre>
+     *
+     * @param array1  the first array whose elements are added to the new array, may be <code>null</code>
+     * @param array2  the second array whose elements are added to the new array, may be <code>null</code>
+     * @return The new array, <code>null</code> if <code>null</code> array inputs. 
+     *      The type of the new array is the type of the first array.
+     * @since 2.1
+     */
+    public static Object[] addAll(Object[] array1, Object[] array2) {
+        if (array1 == null) {
+            return clone(array2);
+        } else if (array2 == null) {
+            return clone(array1);
+        } else {
+            Object[] joinedArray = (Object[]) Array.newInstance(array1.getClass().getComponentType(), array1.length
+                + array2.length);
+            System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+            System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+            return joinedArray;
+        }
+    }
+
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, null)      = [null]
+     * ArrayUtils.add(null, "a")       = ["a"]
+     * ArrayUtils.add(["a"], null)     = ["a", null]
+     * ArrayUtils.add(["a"], "b")      = ["a", "b"]
+     * ArrayUtils.add(["a", "b"], "c") = ["a", "b", "c"]
+     * </pre>
+     * 
+     * @param array  the array to "add" the element to, may be <code>null</code>
+     * @param element  the object to add
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static Object[] add(Object[] array, Object element) {
+        Object newArray = copyArrayGrow1(array, element != null ? element.getClass() : Object.class);
+        Array.set(newArray, lastIndex(newArray), element);
+        return (Object[]) newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, true)          = [true]
+     * ArrayUtils.add([true], false)       = [true, false]
+     * ArrayUtils.add([true, false], true) = [true, false, true]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static boolean[] add(boolean[] array, boolean element) {
+        boolean[] newArray = (boolean[])copyArrayGrow1(array, Boolean.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static byte[] add(byte[] array, byte element) {
+        byte[] newArray = (byte[])copyArrayGrow1(array, Byte.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, '0')       = ['0']
+     * ArrayUtils.add(['1'], '0')      = ['1', '0']
+     * ArrayUtils.add(['1', '0'], '1') = ['1', '0', '1']
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static char[] add(char[] array, char element) {
+        char[] newArray = (char[])copyArrayGrow1(array, Character.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static double[] add(double[] array, double element) {
+        double[] newArray = (double[])copyArrayGrow1(array, Double.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static float[] add(float[] array, float element) {
+        float[] newArray = (float[])copyArrayGrow1(array, Float.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static int[] add(int[] array, int element) {
+        int[] newArray = (int[])copyArrayGrow1(array, Integer.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static long[] add(long[] array, long element) {
+        long[] newArray = (long[])copyArrayGrow1(array, Long.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * <p>Copies the given array and adds the given element at the end of the new array.</p>
+     *
+     * <p>The new array contains the same elements of the input
+     * array plus the given element in the last position. The component type of 
+     * the new array is the same as that of the input array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0)   = [0]
+     * ArrayUtils.add([1], 0)    = [1, 0]
+     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
+     * </pre>
+     * 
+     * @param array  the array to copy and add the element to, may be <code>null</code>
+     * @param element  the object to add at the last index of the new array
+     * @return A new array containing the existing elements plus the new element
+     * @since 2.1
+     */
+    public static short[] add(short[] array, short element) {
+        short[] newArray = (short[])copyArrayGrow1(array, Short.TYPE);
+        newArray[lastIndex(newArray)] = element;
+        return newArray;
+    }
+    
+    /**
+     * Returns a copy of the given array of size 1 greater than the argument. 
+     * The last value of the array is left to the default value.
+     * 
+     * @param array The array to copy, must not be <code>null</code>.
+     * @param newArrayComponentType If <code>array</code> is <code>null</code>, create a 
+     * size 1 array of this type.
+     * @return A new copy of the array of size 1 greater than the input.
+     */    
+    private static Object copyArrayGrow1(Object array, Class newArrayComponentType) {
+        if (array != null) {
+            int arrayLength = Array.getLength(array);
+            Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
+            System.arraycopy(array, 0, newArray, 0, arrayLength);
+            return newArray;
+        } else {
+            return Array.newInstance(newArrayComponentType, 1);
+        }
+    }
+    
+    /**
+     * <p>Inserts the specified element at the specified position in the array. 
+     * Shifts the element currently at that position (if any) and any subsequent
+     * elements to the right (adds one to their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array plus the given element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, a new one element array is returned
+     *  whose component type is the same as the element.</p>
+     * 
+     * <pre>
+     * ArrayUtils.add(null, 0, null)      = [null]
+     * ArrayUtils.add(null, 0, "a")       = ["a"]
+     * ArrayUtils.add(["a"], 1, null)     = ["a", null]
+     * ArrayUtils.add(["a"], 1, "b")      = ["a", "b"]
+     * ArrayUtils.add(["a", "b"], 3, "c") = ["a", "b", "c"]
+     * </pre>
+     * 
+     * @param array  the array to add the element to, may be <code>null</code>
+     * @param index  the position of the new object
+     * @param element  the object to add
+     * @return A new array containing the existing elements and the new element
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index > array.length).
+     */
+    public static Object[] add(Object[] array, int index, Object element) {
+        if (array == null) {
+            if (index != 0) {
+                throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0");
+            }
+            Object joinedArray = Array.newInstance(element != null ? element.getClass() : Object.class, 1);
+            Array.set(joinedArray, 0, element);
+            return (Object[]) joinedArray;
+        }
+        int length = array.length;
+        if (index > length || index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+        }
+        Object result = Array.newInstance(array.getClass().getComponentType(), length + 1);
+        System.arraycopy(array, 0, result, 0, index);
+        Array.set(result, index, element);
+        if (index < length) {
+            System.arraycopy(array, index, result, index + 1, length - index);
+        }
+        return (Object[]) result;
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove(["a"], 0)           = []
+     * ArrayUtils.remove(["a", "b"], 0)      = ["b"]
+     * ArrayUtils.remove(["a", "b"], 1)      = ["a"]
+     * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static Object[] remove(Object[] array, int index) {
+        return (Object[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, "a")            = null
+     * ArrayUtils.removeElement([], "a")              = []
+     * ArrayUtils.removeElement(["a"], "b")           = ["a"]
+     * ArrayUtils.removeElement(["a", "b"], "a")      = ["b"]
+     * ArrayUtils.removeElement(["a", "b", "a"], "a") = ["b", "a"]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static Object[] removeElement(Object[] array, Object element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([true], 0)              = []
+     * ArrayUtils.remove([true, false], 0)       = [false]
+     * ArrayUtils.remove([true, false], 1)       = [true]
+     * ArrayUtils.remove([true, true, false], 1) = [true, false]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static boolean[] remove(boolean[] array, int index) {
+        return (boolean[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, true)                = null
+     * ArrayUtils.removeElement([], true)                  = []
+     * ArrayUtils.removeElement([true], false)             = [true]
+     * ArrayUtils.removeElement([true, false], false)      = [true]
+     * ArrayUtils.removeElement([true, false, true], true) = [false, true]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static boolean[] removeElement(boolean[] array, boolean element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1], 0)          = []
+     * ArrayUtils.remove([1, 0], 0)       = [0]
+     * ArrayUtils.remove([1, 0], 1)       = [1]
+     * ArrayUtils.remove([1, 0, 1], 1)    = [1, 1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static byte[] remove(byte[] array, int index) {
+        return (byte[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1)        = null
+     * ArrayUtils.removeElement([], 1)          = []
+     * ArrayUtils.removeElement([1], 0)         = [1]
+     * ArrayUtils.removeElement([1, 0], 0)      = [1]
+     * ArrayUtils.removeElement([1, 0, 1], 1)   = [0, 1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static byte[] removeElement(byte[] array, byte element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove(['a'], 0)           = []
+     * ArrayUtils.remove(['a', 'b'], 0)      = ['b']
+     * ArrayUtils.remove(['a', 'b'], 1)      = ['a']
+     * ArrayUtils.remove(['a', 'b', 'c'], 1) = ['a', 'c']
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static char[] remove(char[] array, int index) {
+        return (char[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 'a')            = null
+     * ArrayUtils.removeElement([], 'a')              = []
+     * ArrayUtils.removeElement(['a'], 'b')           = ['a']
+     * ArrayUtils.removeElement(['a', 'b'], 'a')      = ['b']
+     * ArrayUtils.removeElement(['a', 'b', 'a'], 'a') = ['b', 'a']
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static char[] removeElement(char[] array, char element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1.1], 0)           = []
+     * ArrayUtils.remove([2.5, 6.0], 0)      = [6.0]
+     * ArrayUtils.remove([2.5, 6.0], 1)      = [2.5]
+     * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static double[] remove(double[] array, int index) {
+        return (double[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1.1)            = null
+     * ArrayUtils.removeElement([], 1.1)              = []
+     * ArrayUtils.removeElement([1.1], 1.2)           = [1.1]
+     * ArrayUtils.removeElement([1.1, 2.3], 1.1)      = [2.3]
+     * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static double[] removeElement(double[] array, double element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1.1], 0)           = []
+     * ArrayUtils.remove([2.5, 6.0], 0)      = [6.0]
+     * ArrayUtils.remove([2.5, 6.0], 1)      = [2.5]
+     * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static float[] remove(float[] array, int index) {
+        return (float[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1.1)            = null
+     * ArrayUtils.removeElement([], 1.1)              = []
+     * ArrayUtils.removeElement([1.1], 1.2)           = [1.1]
+     * ArrayUtils.removeElement([1.1, 2.3], 1.1)      = [2.3]
+     * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static float[] removeElement(float[] array, float element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1], 0)         = []
+     * ArrayUtils.remove([2, 6], 0)      = [6]
+     * ArrayUtils.remove([2, 6], 1)      = [2]
+     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static int[] remove(int[] array, int index) {
+        return (int[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1)      = null
+     * ArrayUtils.removeElement([], 1)        = []
+     * ArrayUtils.removeElement([1], 2)       = [1]
+     * ArrayUtils.removeElement([1, 3], 1)    = [3]
+     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static int[] removeElement(int[] array, int element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1], 0)         = []
+     * ArrayUtils.remove([2, 6], 0)      = [6]
+     * ArrayUtils.remove([2, 6], 1)      = [2]
+     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static long[] remove(long[] array, int index) {
+        return (long[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1)      = null
+     * ArrayUtils.removeElement([], 1)        = []
+     * ArrayUtils.removeElement([1], 2)       = [1]
+     * ArrayUtils.removeElement([1, 3], 1)    = [3]
+     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static long[] removeElement(long[] array, long element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     *
+     * <pre>
+     * ArrayUtils.remove([1], 0)         = []
+     * ArrayUtils.remove([2, 6], 0)      = [6]
+     * ArrayUtils.remove([2, 6], 1)      = [2]
+     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    public static short[] remove(short[] array, int index) {
+        return (short[]) remove((Object) array, index);
+    }
+    
+    /**
+     * <p>Removes the first occurrence of the specified element from the
+     * specified array. All subsequent elements are shifted to the left 
+     * (substracts one from their indices). If the array doesn't contains
+     * such an element, no elements are removed from the array.</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the first occurrence of the specified element. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <pre>
+     * ArrayUtils.removeElement(null, 1)      = null
+     * ArrayUtils.removeElement([], 1)        = []
+     * ArrayUtils.removeElement([1], 2)       = [1]
+     * ArrayUtils.removeElement([1, 3], 1)    = [3]
+     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
+     * </pre>
+     * 
+     * @param array  the array to remove the element from, may be <code>null</code>
+     * @param element  the element to be removed
+     * @return A new array containing the existing elements except the first
+     *         occurrence of the specified element.
+     * @since 2.1
+     */
+    public static short[] removeElement(short[] array, short element) {
+        int index = indexOf(array, element);
+        if (index == -1) {
+            return clone(array);
+        } 
+        return remove(array, index);
+    }
+    
+    /**
+     * <p>Removes the element at the specified position from the specified array.
+     * All subsequent elements are shifted to the left (substracts one from
+     * their indices).</p>
+     *
+     * <p>This method returns a new array with the same elements of the input
+     * array except the element on the specified position. The component 
+     * type of the returned array is always the same as that of the input 
+     * array.</p>
+     *
+     * <p>If the input array is <code>null</code>, an IndexOutOfBoundsException
+     * will be thrown, because in that case no valid index can be specified.</p>
+     * 
+     * @param array  the array to remove the element from, may not be <code>null</code>
+     * @param index  the position of the element to be removed
+     * @return A new array containing the existing elements except the element
+     *         at the specified position.
+     * @throws IndexOutOfBoundsException if the index is out of range 
+     * (index < 0 || index >= array.length), or if the array is <code>null</code>.
+     * @since 2.1
+     */
+    private static Object remove(Object array, int index) {
+        int length = getLength(array);
+        if (index < 0 || index >= length) {
+            throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+        }
+        
+        Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
+        System.arraycopy(array, 0, result, 0, index);
+        if (index < length - 1) {
+            System.arraycopy(array, index + 1, result, index, length - index - 1);
+        }
+        
+        return result;
+    }
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/BooleanUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/BooleanUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,889 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+/**
+ * <p>Operations on boolean primitives and Boolean objects.</p>
+ *
+ * <p>This class tries to handle <code>null</code> input gracefully.
+ * An exception will not be thrown for a <code>null</code> input.
+ * Each method documents its behaviour in more detail.</p>
+ * 
+ * @author Stephen Colebourne
+ * @author Matthew Hawthorne
+ * @author Gary Gregory
+ * @since 2.0
+ * @version $Id: BooleanUtils.java,v 1.18 2004/02/18 22:59:50 ggregory Exp $
+ */
+public class BooleanUtils {
+    private static final Integer INTEGER_ZERO = new Integer( 0 );
+    private static final Integer INTEGER_ONE = new Integer( 1 );
+
+    /**
+     * <p><code>BooleanUtils</code> instances should NOT be constructed in standard programming.
+     * Instead, the class should be used as <code>BooleanUtils.toBooleanObject(true);</code>.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean instance
+     * to operate.</p>
+     */
+    public BooleanUtils() {
+    }
+
+    // Boolean utilities
+    //--------------------------------------------------------------------------
+    /**
+     * <p>Negates the specified boolean.</p>
+     * 
+     * <p>If <code>null</code> is passed in, <code>null</code> will be returned.</p>
+     *
+     * <pre>
+     *   BooleanUtils.negate(Boolean.TRUE)  = Boolean.FALSE;
+     *   BooleanUtils.negate(Boolean.FALSE) = Boolean.TRUE;
+     *   BooleanUtils.negate(null)          = null;
+     * </pre>
+     * 
+     * @param bool  the Boolean to negate, may be null
+     * @return the negated Boolean, or <code>null</code> if <code>null</code> input
+     */
+    public static Boolean negate(Boolean bool) {
+        if (bool == null) {
+            return null;
+        }
+        return (bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE);
+    }
+    
+    // boolean Boolean methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Boolean factory that avoids creating new Boolean objecs all the time.</p>
+     * 
+     * <p>This method was added to JDK1.4 but is available here for earlier JDKs.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBooleanObject(false) = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject(true)  = Boolean.TRUE
+     * </pre>
+     *
+     * @param bool  the boolean to convert
+     * @return Boolean.TRUE or Boolean.FALSE as appropriate
+     */
+    public static Boolean toBooleanObject(boolean bool) {
+        return (bool ? Boolean.TRUE : Boolean.FALSE);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a boolean handling <code>null</code>
+     * by returning <code>false</code>.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBoolean(Boolean.TRUE)  = true
+     *   BooleanUtils.toBoolean(Boolean.FALSE) = false
+     *   BooleanUtils.toBoolean(null)          = false
+     * </pre>
+     *
+     * @param bool  the boolean to convert
+     * @return <code>true</code> or <code>false</code>, 
+     *  <code>null</code> returns <code>false</code>
+     */
+    public static boolean toBoolean(Boolean bool) {
+        if (bool == null) {
+            return false;
+        }
+        return (bool.booleanValue() ? true : false);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a boolean handling <code>null</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false) = true
+     *   BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true) = false
+     *   BooleanUtils.toBooleanDefaultIfNull(null, true)          = true
+     * </pre>
+     *
+     * @param bool  the boolean to convert
+     * @param valueIfNull  the boolean value to return if <code>null</code>
+     * @return <code>true</code> or <code>false</code>
+     */
+    public static boolean toBooleanDefaultIfNull(Boolean bool, boolean valueIfNull) {
+        if (bool == null) {
+            return valueIfNull;
+        }
+        return (bool.booleanValue() ? true : false);
+    }
+    
+    // Integer to Boolean methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts an int to a boolean using the convention that <code>zero</code>
+     * is <code>false</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBoolean(0) = false
+     *   BooleanUtils.toBoolean(1) = true
+     *   BooleanUtils.toBoolean(2) = true
+     * </pre>
+     *
+     * @param value  the int to convert
+     * @return <code>true</code> if non-zero, <code>false</code>
+     *  if zero
+     */
+    public static boolean toBoolean(int value) {
+        return (value == 0 ? false : true);
+    }
+    
+    /**
+     * <p>Converts an int to a Boolean using the convention that <code>zero</code>
+     * is <code>false</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBoolean(0) = Boolean.FALSE
+     *   BooleanUtils.toBoolean(1) = Boolean.TRUE
+     *   BooleanUtils.toBoolean(2) = Boolean.TRUE
+     * </pre>
+     *
+     * @param value  the int to convert
+     * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
+     *  <code>null</code> if <code>null</code>
+     */
+    public static Boolean toBooleanObject(int value) {
+        return (value == 0 ? Boolean.FALSE : Boolean.TRUE);
+    }
+    
+    /**
+     * <p>Converts an Integer to a Boolean using the convention that <code>zero</code>
+     * is <code>false</code>.</p>
+     * 
+     * <p><code>null</code> will be converted to <code>null</code>.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBoolean(new Integer(0))    = Boolean.FALSE
+     *   BooleanUtils.toBoolean(new Integer(1))    = Boolean.TRUE
+     *   BooleanUtils.toBoolean(new Integer(null)) = null
+     * </pre>
+     *
+     * @param value  the Integer to convert
+     * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
+     *  <code>null</code> if <code>null</code> input
+     */
+    public static Boolean toBooleanObject(Integer value) {
+        if (value == null) {
+            return null;
+        }
+        return (value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE);
+    }
+    
+    /**
+     * <p>Converts an int to a boolean specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBoolean(0, 1, 0) = false
+     *   BooleanUtils.toBoolean(1, 1, 0) = true
+     *   BooleanUtils.toBoolean(2, 1, 2) = false
+     *   BooleanUtils.toBoolean(2, 2, 0) = true
+     * </pre>
+     *
+     * @param value  the Integer to convert
+     * @param trueValue  the value to match for <code>true</code>
+     * @param falseValue  the value to match for <code>false</code>
+     * @return <code>true</code> or <code>false</code>
+     * @throws IllegalArgumentException if no match
+     */
+    public static boolean toBoolean(int value, int trueValue, int falseValue) {
+        if (value == trueValue) {
+            return true;
+        } else if (value == falseValue) {
+            return false;
+        }
+        // no match
+        throw new IllegalArgumentException("The Integer did not match either specified value");
+    }
+    
+    /**
+     * <p>Converts an Integer to a boolean specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBoolean(new Integer(0), new Integer(1), new Integer(0)) = false
+     *   BooleanUtils.toBoolean(new Integer(1), new Integer(1), new Integer(0)) = true
+     *   BooleanUtils.toBoolean(new Integer(2), new Integer(1), new Integer(2)) = false
+     *   BooleanUtils.toBoolean(new Integer(2), new Integer(2), new Integer(0)) = true
+     *   BooleanUtils.toBoolean(null, null, new Integer(0))                     = true
+     * </pre>
+     *
+     * @param value  the Integer to convert
+     * @param trueValue  the value to match for <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseValue  the value to match for <code>false</code>,
+     *  may be <code>null</code>
+     * @return <code>true</code> or <code>false</code>
+     * @throws IllegalArgumentException if no match
+     */
+    public static boolean toBoolean(Integer value, Integer trueValue, Integer falseValue) {
+        if (value == null) {
+            if (trueValue == null) {
+                return true;
+            } else if (falseValue == null) {
+                return false;
+            }
+        } else if (value.equals(trueValue)) {
+            return true;
+        } else if (value.equals(falseValue)) {
+            return false;
+        }
+        // no match
+        throw new IllegalArgumentException("The Integer did not match either specified value");
+    }
+    
+    /**
+     * <p>Converts an int to a Boolean specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBooleanObject(0, 0, 2, 3) = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject(2, 1, 2, 3) = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject(3, 1, 2, 3) = null
+     * </pre>
+     *
+     * @param value  the Integer to convert
+     * @param trueValue  the value to match for <code>true</code>
+     * @param falseValue  the value to match for <code>false</code>
+     * @param nullValue  the value to to match for <code>null</code>
+     * @return Boolean.TRUE, Boolean.FALSE, or <code>null</code>
+     * @throws IllegalArgumentException if no match
+     */
+    public static Boolean toBooleanObject(int value, int trueValue, int falseValue, int nullValue) {
+        if (value == trueValue) {
+            return Boolean.TRUE;
+        } else if (value == falseValue) {
+            return Boolean.FALSE;
+        } else if (value == nullValue) {
+            return null;
+        }
+        // no match
+        throw new IllegalArgumentException("The Integer did not match any specified value");
+    }
+    
+    /**
+     * <p>Converts an Integer to a Boolean specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toBooleanObject(new Integer(0), new Integer(0), new Integer(2), new Integer(3)) = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject(new Integer(2), new Integer(1), new Integer(2), new Integer(3)) = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject(new Integer(3), new Integer(1), new Integer(2), new Integer(3)) = null
+     * </pre>
+     *
+     * @param value  the Integer to convert
+     * @param trueValue  the value to match for <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseValue  the value to match for <code>false</code>,
+     *  may be <code>null</code>
+     * @param nullValue  the value to to match for <code>null</code>,
+     *  may be <code>null</code>
+     * @return Boolean.TRUE, Boolean.FALSE, or <code>null</code>
+     * @throws IllegalArgumentException if no match
+     */
+    public static Boolean toBooleanObject(Integer value, Integer trueValue, Integer falseValue, Integer nullValue) {
+        if (value == null) {
+            if (trueValue == null) {
+                return Boolean.TRUE;
+            } else if (falseValue == null) {
+                return Boolean.FALSE;
+            } else if (nullValue == null) {
+                return null;
+            }
+        } else if (value.equals(trueValue)) {
+            return Boolean.TRUE;
+        } else if (value.equals(falseValue)) {
+            return Boolean.FALSE;
+        } else if (value.equals(nullValue)) {
+            return null;
+        }
+        // no match
+        throw new IllegalArgumentException("The Integer did not match any specified value");
+    }
+    
+    // Boolean to Integer methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a boolean to an int using the convention that
+     * <code>zero</code> is <code>false</code>.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toInteger(true)  = 1
+     *   BooleanUtils.toInteger(false) = 0
+     * </pre>
+     *
+     * @param bool  the boolean to convert
+     * @return one if <code>true</code>, zero if <code>false</code>
+     */
+    public static int toInteger(boolean bool) {
+        return (bool ? 1 : 0);
+    }
+    
+    /**
+     * <p>Converts a boolean to an Integer using the convention that
+     * <code>zero</code> is <code>false</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toIntegerObject(true)  = new Integer(1)
+     *   BooleanUtils.toIntegerObject(false) = new Integer(0)
+     * </pre>
+     *
+     * @param bool  the boolean to convert
+     * @return one if <code>true</code>, zero if <code>false</code>
+     */
+    public static Integer toIntegerObject(boolean bool) {
+        return (bool ? INTEGER_ONE : INTEGER_ZERO);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a Integer using the convention that
+     * <code>zero</code> is <code>false</code>.</p>
+     *
+     * <p><code>null</code> will be converted to <code>null</code>.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toIntegerObject(Boolean.TRUE)  = new Integer(1)
+     *   BooleanUtils.toIntegerObject(Boolean.FALSE) = new Integer(0)
+     * </pre>
+     *
+     * @param bool  the Boolean to convert
+     * @return one if Boolean.TRUE, zero if Boolean.FALSE, <code>null</code> if <code>null</code>
+     */
+    public static Integer toIntegerObject(Boolean bool) {
+        if (bool == null) {
+            return null;
+        }
+        return (bool.booleanValue() ? INTEGER_ONE : INTEGER_ZERO);
+    }
+    
+    /**
+     * <p>Converts a boolean to an int specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toInteger(true, 1, 0)  = 1
+     *   BooleanUtils.toInteger(false, 1, 0) = 0
+     * </pre>
+     *
+     * @param bool  the to convert
+     * @param trueValue  the value to return if <code>true</code>
+     * @param falseValue  the value to return if <code>false</code>
+     * @return the appropriate value
+     */
+    public static int toInteger(boolean bool, int trueValue, int falseValue) {
+        return (bool ? trueValue : falseValue);
+    }
+    
+    /**
+     * <p>Converts a Boolean to an int specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toInteger(Boolean.TRUE, 1, 0, 2)  = 1
+     *   BooleanUtils.toInteger(Boolean.FALSE, 1, 0, 2) = 0
+     *   BooleanUtils.toInteger(null, 1, 0, 2)          = 2
+     * </pre>
+     *
+     * @param bool  the Boolean to convert
+     * @param trueValue  the value to return if <code>true</code>
+     * @param falseValue  the value to return if <code>false</code>
+     * @param nullValue  the value to return if <code>null</code>
+     * @return the appropriate value
+     */
+    public static int toInteger(Boolean bool, int trueValue, int falseValue, int nullValue) {
+        if (bool == null) {
+            return nullValue;
+        }
+        return (bool.booleanValue() ? trueValue : falseValue);
+    }
+    
+    /**
+     * <p>Converts a boolean to an Integer specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toIntegerObject(true, new Integer(1), new Integer(0))  = new Integer(1)
+     *   BooleanUtils.toIntegerObject(false, new Integer(1), new Integer(0)) = new Integer(0)
+     * </pre>
+     *
+     * @param bool  the to convert
+     * @param trueValue  the value to return if <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseValue  the value to return if <code>false</code>,
+     *  may be <code>null</code>
+     * @return the appropriate value
+     */
+    public static Integer toIntegerObject(boolean bool, Integer trueValue, Integer falseValue) {
+        return (bool ? trueValue : falseValue);
+    }
+    
+    /**
+     * <p>Converts a Boolean to an Integer specifying the conversion values.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toIntegerObject(Boolean.TRUE, new Integer(1), new Integer(0), new Integer(2))  = new Integer(1)
+     *   BooleanUtils.toIntegerObject(Boolean.FALSE, new Integer(1), new Integer(0), new Integer(2)) = new Integer(0)
+     *   BooleanUtils.toIntegerObject(null, new Integer(1), new Integer(0), new Integer(2))          = new Integer(2)
+     * </pre>
+     *
+     * @param bool  the Boolean to convert
+     * @param trueValue  the value to return if <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseValue  the value to return if <code>false</code>,
+     *  may be <code>null</code>
+     * @param nullValue  the value to return if <code>null</code>,
+     *  may be <code>null</code>
+     * @return the appropriate value
+     */
+    public static Integer toIntegerObject(Boolean bool, Integer trueValue, Integer falseValue, Integer nullValue) {
+        if (bool == null) {
+            return nullValue;
+        }
+        return (bool.booleanValue() ? trueValue : falseValue);
+    }
+    
+    // String to Boolean methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a String to a Boolean.</p>
+     * 
+     * <p><code>'true'</code>, <code>'on'</code> or <code>'yes'</code>
+     * (case insensitive) will return <code>true</code>.
+     * <code>'false'</code>, <code>'off'</code> or <code>'no'</code>
+     * (case insensitive) will return <code>false</code>.
+     * Otherwise, <code>null</code> is returned.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBooleanObject(null)    = null
+     *   BooleanUtils.toBooleanObject("true")  = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject("false") = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject("on")    = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject("ON")    = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject("off")   = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject("oFf")   = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject("blue")  = null
+     * </pre>
+     *
+     * @param str  the String to check
+     * @return the Boolean value of the string,
+     *  <code>null</code> if no match or <code>null</code> input
+     */
+    public static Boolean toBooleanObject(String str) {
+        if ("true".equalsIgnoreCase(str)) {
+            return Boolean.TRUE;
+        } else if ("false".equalsIgnoreCase(str)) {
+            return Boolean.FALSE;
+        } else if ("on".equalsIgnoreCase(str)) {
+            return Boolean.TRUE;
+        } else if ("off".equalsIgnoreCase(str)) {
+            return Boolean.FALSE;
+        } else if ("yes".equalsIgnoreCase(str)) {
+            return Boolean.TRUE;
+        } else if ("no".equalsIgnoreCase(str)) {
+            return Boolean.FALSE;
+        }
+        // no match
+        return null;
+    }
+
+    /**
+     * <p>Converts a String to a Boolean throwing an exception if no match.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBooleanObject("true", "true", "false", "null")  = Boolean.TRUE
+     *   BooleanUtils.toBooleanObject("false", "true", "false", "null") = Boolean.FALSE
+     *   BooleanUtils.toBooleanObject("null", "true", "false", "null")  = null
+     * </pre>
+     *
+     * @param str  the String to check
+     * @param trueString  the String to match for <code>true</code>
+     *  (case sensitive), may be <code>null</code>
+     * @param falseString  the String to match for <code>false</code>
+     *  (case sensitive), may be <code>null</code>
+     * @param nullString  the String to match for <code>null</code>
+     *  (case sensitive), may be <code>null</code>
+     * @return the Boolean value of the string,
+     *  <code>null</code> if no match or <code>null</code> input
+     */
+    public static Boolean toBooleanObject(String str, String trueString, String falseString, String nullString) {
+        if (str == null) {
+            if (trueString == null) {
+                return Boolean.TRUE;
+            } else if (falseString == null) {
+                return Boolean.FALSE;
+            } else if (nullString == null) {
+                return null;
+            }
+        } else if (str.equals(trueString)) {
+            return Boolean.TRUE;
+        } else if (str.equals(falseString)) {
+            return Boolean.FALSE;
+        } else if (str.equals(nullString)) {
+            return null;
+        }
+        // no match
+        throw new IllegalArgumentException("The String did not match any specified value");
+    }
+
+    // String to boolean methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a String to a boolean (optimised for performance).</p>
+     * 
+     * <p><code>'true'</code>, <code>'on'</code> or <code>'yes'</code>
+     * (case insensitive) will return <code>true</code>. Otherwise,
+     * <code>false</code> is returned.</p>
+     * 
+     * <p>This method performs 4 times faster (JDK1.4) than
+     * <code>Boolean.valueOf(String)</code>. However, this method accepts
+     * 'on' and 'yes' as true values.
+     *
+     * <pre>
+     *   BooleanUtils.toBoolean(null)    = false
+     *   BooleanUtils.toBoolean("true")  = true
+     *   BooleanUtils.toBoolean("TRUE")  = true
+     *   BooleanUtils.toBoolean("tRUe")  = true
+     *   BooleanUtils.toBoolean("on")    = true
+     *   BooleanUtils.toBoolean("yes")   = true
+     *   BooleanUtils.toBoolean("false") = false
+     *   BooleanUtils.toBoolean("x gti") = false
+     * </pre>
+     *
+     * @param str  the String to check
+     * @return the boolean value of the string, <code>false</code> if no match
+     */
+    public static boolean toBoolean(String str) {
+        // Previously used equalsIgnoreCase, which was fast for interned 'true'.
+        // Non interned 'true' matched 15 times slower.
+        // 
+        // Optimisation provides same performance as before for interned 'true'.
+        // Similar performance for null, 'false', and other strings not length 2/3/4.
+        // 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower.
+        if (str == "true") {
+            return true;
+        }
+        if (str == null) {
+            return false;
+        }
+        switch (str.length()) {
+            case 2: {
+                char ch0 = str.charAt(0);
+                char ch1 = str.charAt(1);
+                return 
+                    (ch0 == 'o' || ch0 == 'O') &&
+                    (ch1 == 'n' || ch1 == 'N');
+            }
+            case 3: {
+                char ch = str.charAt(0);
+                if (ch == 'y') {
+                    return 
+                        (str.charAt(1) == 'e' || str.charAt(1) == 'E') &&
+                        (str.charAt(2) == 's' || str.charAt(2) == 'S');
+                }
+                if (ch == 'Y') {
+                    return 
+                        (str.charAt(1) == 'E' || str.charAt(1) == 'e') &&
+                        (str.charAt(2) == 'S' || str.charAt(2) == 's');
+                }
+            }
+            case 4: {
+                char ch = str.charAt(0);
+                if (ch == 't') {
+                    return 
+                        (str.charAt(1) == 'r' || str.charAt(1) == 'R') &&
+                        (str.charAt(2) == 'u' || str.charAt(2) == 'U') &&
+                        (str.charAt(3) == 'e' || str.charAt(3) == 'E');
+                }
+                if (ch == 'T') {
+                    return 
+                        (str.charAt(1) == 'R' || str.charAt(1) == 'r') &&
+                        (str.charAt(2) == 'U' || str.charAt(2) == 'u') &&
+                        (str.charAt(3) == 'E' || str.charAt(3) == 'e');
+                }
+            }
+        }
+        return false;
+    }
+    
+//    public static void main(String[] args) {
+//        long start = System.currentTimeMillis();
+//        boolean flag = true;
+//        int count = 0;
+//        for (int i = 0; i < 100000000; i++) {
+//            flag = toBoolean("YES");
+//        }
+//        long end = System.currentTimeMillis();
+//        System.out.println((end - start) + " " + flag + " " + count);
+//    }
+    
+    /**
+     * <p>Converts a String to a Boolean throwing an exception if no match found.</p>
+     * 
+     * <p>null is returned if there is no match.</p>
+     *
+     * <pre>
+     *   BooleanUtils.toBoolean("true", "true", "false")  = true
+     *   BooleanUtils.toBoolean("false", "true", "false") = false
+     * </pre>
+     *
+     * @param str  the String to check
+     * @param trueString  the String to match for <code>true</code>
+     *  (case sensitive), may be <code>null</code>
+     * @param falseString  the String to match for <code>false</code>
+     *  (case sensitive), may be <code>null</code>
+     * @return the boolean value of the string
+     * @throws IllegalArgumentException if the String doesn't match
+     */
+    public static boolean toBoolean(String str, String trueString, String falseString) {
+        if (str == null) {
+            if (trueString == null) {
+                return true;
+            } else if (falseString == null) {
+                return false;
+            }
+        } else if (str.equals(trueString)) {
+            return true;
+        } else if (str.equals(falseString)) {
+            return false;
+        }
+        // no match
+        throw new IllegalArgumentException("The String did not match either specified value");
+    }
+
+    // Boolean to String methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a Boolean to a String returning <code>'true'</code>,
+     * <code>'false'</code>, or <code>null</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringTrueFalse(Boolean.TRUE)  = "true"
+     *   BooleanUtils.toStringTrueFalse(Boolean.FALSE) = "false"
+     *   BooleanUtils.toStringTrueFalse(null)          = null;
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'true'</code>, <code>'false'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringTrueFalse(Boolean bool) {
+        return toString(bool, "true", "false", null);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a String returning <code>'on'</code>,
+     * <code>'off'</code>, or <code>null</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringOnOff(Boolean.TRUE)  = "on"
+     *   BooleanUtils.toStringOnOff(Boolean.FALSE) = "off"
+     *   BooleanUtils.toStringOnOff(null)          = null;
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'on'</code>, <code>'off'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringOnOff(Boolean bool) {
+        return toString(bool, "on", "off", null);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a String returning <code>'yes'</code>,
+     * <code>'no'</code>, or <code>null</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringYesNo(Boolean.TRUE)  = "yes"
+     *   BooleanUtils.toStringYesNo(Boolean.FALSE) = "no"
+     *   BooleanUtils.toStringYesNo(null)          = null;
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'yes'</code>, <code>'no'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringYesNo(Boolean bool) {
+        return toString(bool, "yes", "no", null);
+    }
+    
+    /**
+     * <p>Converts a Boolean to a String returning one of the input Strings.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toString(Boolean.TRUE, "true", "false", null)   = "true"
+     *   BooleanUtils.toString(Boolean.FALSE, "true", "false", null)  = "false"
+     *   BooleanUtils.toString(null, "true", "false", null)           = null;
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @param trueString  the String to return if <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseString  the String to return if <code>false</code>,
+     *  may be <code>null</code>
+     * @param nullString  the String to return if <code>null</code>,
+     *  may be <code>null</code>
+     * @return one of the three input Strings
+     */
+    public static String toString(Boolean bool, String trueString, String falseString, String nullString) {
+        if (bool == null) {
+            return nullString;
+        }
+        return (bool.booleanValue() ? trueString : falseString);
+    }
+    
+    // boolean to String methods
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a boolean to a String returning <code>'true'</code>
+     * or <code>'false'</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringTrueFalse(true)   = "true"
+     *   BooleanUtils.toStringTrueFalse(false)  = "false"
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'true'</code>, <code>'false'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringTrueFalse(boolean bool) {
+        return toString(bool, "true", "false");
+    }
+    
+    /**
+     * <p>Converts a boolean to a String returning <code>'on'</code>
+     * or <code>'off'</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringOnOff(true)   = "on"
+     *   BooleanUtils.toStringOnOff(false)  = "off"
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'on'</code>, <code>'off'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringOnOff(boolean bool) {
+        return toString(bool, "on", "off");
+    }
+    
+    /**
+     * <p>Converts a boolean to a String returning <code>'yes'</code>
+     * or <code>'no'</code>.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toStringYesNo(true)   = "yes"
+     *   BooleanUtils.toStringYesNo(false)  = "no"
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @return <code>'yes'</code>, <code>'no'</code>,
+     *  or <code>null</code>
+     */
+    public static String toStringYesNo(boolean bool) {
+        return toString(bool, "yes", "no");
+    }
+    
+    /**
+     * <p>Converts a boolean to a String returning one of the input Strings.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.toString(true, "true", "false")   = "true"
+     *   BooleanUtils.toString(false, "true", "false")  = "false"
+     * </pre>
+     *
+     * @param bool  the Boolean to check
+     * @param trueString  the String to return if <code>true</code>,
+     *  may be <code>null</code>
+     * @param falseString  the String to return if <code>false</code>,
+     *  may be <code>null</code>
+     * @return one of the two input Strings
+     */
+    public static String toString(boolean bool, String trueString, String falseString) {
+        return (bool ? trueString : falseString);
+    }
+    
+    // xor methods
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Performs an xor on a set of booleans.</p>
+     *
+     * <pre>
+     *   BooleanUtils.xor(new boolean[] { true, true })   = false
+     *   BooleanUtils.xor(new boolean[] { false, false }) = false
+     *   BooleanUtils.xor(new boolean[] { true, false })  = true
+     * </pre>
+     *
+     * @param array  an array of <code>boolean<code>s
+     * @return <code>true</code> if the xor is successful.
+     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
+     * @throws IllegalArgumentException if <code>array</code> is empty.
+     */
+    public static boolean xor(boolean[] array) {
+        // Validates input
+        if (array == null) {
+            throw new IllegalArgumentException("The Array must not be null");
+        } else if (array.length == 0) {
+            throw new IllegalArgumentException("Array is empty");
+        }
+
+        // Loops through array, comparing each item
+        int trueCount = 0;
+        for (int i = 0; i < array.length; i++) {
+            // If item is true, and trueCount is < 1, increments count
+            // Else, xor fails
+            if (array[i]) {
+                if (trueCount < 1) {
+                    trueCount++;
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        // Returns true if there was exactly 1 true item
+        return trueCount == 1;
+    }
+
+    /**
+     * <p>Performs an xor on an array of Booleans.</p>
+     * 
+     * <pre>
+     *   BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE })   = Boolean.FALSE
+     *   BooleanUtils.xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) = Boolean.FALSE
+     *   BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE })  = Boolean.TRUE
+     * </pre>
+     *
+     * @param array  an array of <code>Boolean<code>s
+     * @return <code>true</code> if the xor is successful.
+     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
+     * @throws IllegalArgumentException if <code>array</code> is empty.
+     * @throws IllegalArgumentException if <code>array</code> contains a <code>null</code>
+     */
+    public static Boolean xor(Boolean[] array) {
+        if (array == null) {
+            throw new IllegalArgumentException("The Array must not be null");
+        } else if (array.length == 0) {
+            throw new IllegalArgumentException("Array is empty");
+        }
+        boolean[] primitive = null;
+        try {
+            primitive = ArrayUtils.toPrimitive(array);
+        } catch (NullPointerException ex) {
+            throw new IllegalArgumentException("The array must not contain any null elements");
+        }
+        return (xor(primitive) ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ClassUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ClassUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,616 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>Operates on classes without using reflection.</p>
+ *
+ * <p>This class handles invalid <code>null</code> inputs as best it can.
+ * Each method documents its behaviour in more detail.</p>
+ *
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Norm Deane
+ * @since 2.0
+ * @version $Id: ClassUtils.java,v 1.30 2004/06/30 18:33:58 ggregory Exp $
+ */
+public class ClassUtils {
+    private static final String EMPTY = "";
+
+
+    /**
+     * <p>The package separator character: <code>'&#x2e;' == {@}</code>.</p>
+     */
+    public static final char PACKAGE_SEPARATOR_CHAR = '.';
+    
+    /**
+     * <p>The package separator String: <code>"&#x2e;"</code>.</p>
+     */
+    public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
+    
+    /**
+     * <p>The inner class separator character: <code>'$' == {@}</code>.</p>
+     */
+    public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
+    
+    /**
+     * <p>The inner class separator String: <code>"$"</code>.</p>
+     */
+    public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
+    
+    /** 
+     * Maps primitive <code>Class</code>es to their corresponding wrapper <code>Class</code>. 
+     */
+    private static Map  primitiveWrapperMap = new HashMap();
+    static {
+         primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
+         primitiveWrapperMap.put(Byte.TYPE, Byte.class);
+         primitiveWrapperMap.put(Character.TYPE, Character.class);
+         primitiveWrapperMap.put(Short.TYPE, Short.class);
+         primitiveWrapperMap.put(Integer.TYPE, Integer.class);
+         primitiveWrapperMap.put(Long.TYPE, Long.class);
+         primitiveWrapperMap.put(Double.TYPE, Double.class);
+         primitiveWrapperMap.put(Float.TYPE, Float.class);
+    }
+    
+    /**
+     * <p>ClassUtils instances should NOT be constructed in standard programming.
+     * Instead, the class should be used as
+     * <code>ClassUtils.getShortClassName(cls)</code>.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean
+     * instance to operate.</p>
+     */
+    public ClassUtils() {
+    }
+
+    // Short class name
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Gets the class name minus the package name for an <code>Object</code>.</p>
+     * 
+     * @param object  the class to get the short name for, may be null
+     * @param valueIfNull  the value to return if null
+     * @return the class name of the object without the package name, or the null value
+     */
+    public static String getShortClassName(Object object, String valueIfNull) {
+        if (object == null) {
+            return valueIfNull;
+        }
+        return getShortClassName(object.getClass().getName());
+    }
+    
+    /**
+     * <p>Gets the class name minus the package name from a <code>Class</code>.</p>
+     * 
+     * @param cls  the class to get the short name for.
+     * @return the class name without the package name or an empty string
+     */
+    public static String getShortClassName(Class cls) {
+        if (cls == null) {
+            return EMPTY;
+        }
+        return getShortClassName(cls.getName());
+    }
+    
+    /**
+     * <p>Gets the class name minus the package name from a String.</p>
+     *
+     * <p>The string passed in is assumed to be a class name - it is not checked.</p>
+     * 
+     * @param className  the className to get the short name for
+     * @return the class name of the class without the package name or an empty string
+     */
+    public static String getShortClassName(String className) {
+        if (className == null) {
+            return EMPTY;
+        }
+        if (className.length() == 0) {
+            return EMPTY;
+        }
+        char[] chars = className.toCharArray();
+        int lastDot = 0;
+        for (int i = 0; i < chars.length; i++) {
+            if (chars[i] == PACKAGE_SEPARATOR_CHAR) {
+                lastDot = i + 1;
+            } else if (chars[i] == INNER_CLASS_SEPARATOR_CHAR) {  // handle inner classes
+                chars[i] = PACKAGE_SEPARATOR_CHAR;
+            }
+        }
+        return new String(chars, lastDot, chars.length - lastDot);
+    }
+    
+    // Package name
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Gets the package name of an <code>Object</code>.</p>
+     * 
+     * @param object  the class to get the package name for, may be null
+     * @param valueIfNull  the value to return if null
+     * @return the package name of the object, or the null value
+     */
+    public static String getPackageName(Object object, String valueIfNull) {
+        if (object == null) {
+            return valueIfNull;
+        }
+        return getPackageName(object.getClass().getName());
+    }
+    
+    /**
+     * <p>Gets the package name of a <code>Class</code>.</p>
+     * 
+     * @param cls  the class to get the package name for, may be <code>null</code>.
+     * @return the package name or an empty string
+     */
+    public static String getPackageName(Class cls) {
+        if (cls == null) {
+            return EMPTY;
+        }
+        return getPackageName(cls.getName());
+    }
+    
+    /**
+     * <p>Gets the package name from a <code>String</code>.</p>
+     *
+     * <p>The string passed in is assumed to be a class name - it is not checked.</p>
+	 * <p>If the class is unpackaged, return an empty string.</p>
+     * 
+     * @param className  the className to get the package name for, may be <code>null</code>
+     * @return the package name or an empty string
+     */
+    public static String getPackageName(String className) {
+        if (className == null) {
+            return EMPTY;
+        }
+        int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+        if (i == -1) {
+            return EMPTY;
+        }
+        return className.substring(0, i);
+    }
+    
+    // Superclasses/Superinterfaces
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Gets a <code>List</code> of superclasses for the given class.</p>
+     * 
+     * @param cls  the class to look up, may be <code>null</code>
+     * @return the <code>List</code> of superclasses in order going up from this one
+     *  <code>null</code> if null input
+     */
+    public static List getAllSuperclasses(Class cls) {
+        if (cls == null) {
+            return null;
+        }
+        List classes = new ArrayList();
+        Class superclass = cls.getSuperclass();
+        while (superclass != null) {
+            classes.add(superclass);
+            superclass = superclass.getSuperclass();
+        }
+        return classes;
+    }
+    
+    /**
+     * <p>Gets a <code>List</code> of all interfaces implemented by the given
+     * class and its superclasses.</p>
+     *
+     * <p>The order is determined by looking through each interface in turn as
+     * declared in the source file and following its hierarchy up. Then each 
+     * superclass is considered in the same way. Later duplicates are ignored, 
+     * so the order is maintained.</p>
+     * 
+     * @param cls  the class to look up, may be <code>null</code>
+     * @return the <code>List</code> of interfaces in order,
+     *  <code>null</code> if null input
+     */
+    public static List getAllInterfaces(Class cls) {
+        if (cls == null) {
+            return null;
+        }
+        List list = new ArrayList();
+        while (cls != null) {
+            Class[] interfaces = cls.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++) {
+                if (list.contains(interfaces[i]) == false) {
+                    list.add(interfaces[i]);
+                }
+                List superInterfaces = getAllInterfaces(interfaces[i]);
+                for (Iterator it = superInterfaces.iterator(); it.hasNext();) {
+                    Class intface = (Class) it.next();
+                    if (list.contains(intface) == false) {
+                        list.add(intface);
+                    }
+                }
+            }
+            cls = cls.getSuperclass();
+        }
+        return list;
+    }
+    
+//    /**
+//     * <p>Gets a <code>List</code> of subclasses of the specified class.</p>
+//     *
+//     * <p>This method searches the classpath to find all the subclasses
+//     * of a particular class available. No classes are loaded, the 
+//     * returned list contains class names, not classes.</p>
+//     *
+//     * @param cls  the class to find subclasses for
+//     * @return the <code>List</code> of subclass String class names
+//     * @throws IllegalArgumentException if the class is <code>null</code>
+//     */
+//    public static List getAllSubclassNames(Class cls) {
+//        if (cls == null) {
+//            throw new IllegalArgumentException("The class must not be null");
+//        }
+//        // TODO Use JavaWorld tip for searching the classpath
+//        return null;
+//    }
+
+//    /**
+//     * <p>Gets a <code>List</code> of subclasses of the specified class.</p>
+//     *
+//     * <p>This method searches the classpath to find all the subclasses
+//     * of a particular class available.</p>
+//     *
+//     * @param cls  the class to find subclasses for
+//     * @return the <code>List</code> of subclasses
+//     * @throws IllegalArgumentException if the class is <code>null</code>
+//     */
+//    public static List getAllSubclasses(Class cls) {
+//        List names = getAllSubclassNames(cls);
+//        return convertClassNamesToClasses(names);
+//    }
+
+//    /**
+//     * <p>Gets a <code>List</code> of implementations of the specified interface.</p>
+//     *
+//     * <p>This method searches the classpath to find all the implementations
+//     * of a particular interface available. No classes are loaded, the 
+//     * returned list contains class names, not classes.</p>
+//     *
+//     * @param cls  the class to find sub classes for
+//     * @return the <code>List</code> of implementation String class names
+//     * @throws IllegalArgumentException if the class is <code>null</code>
+//     */
+//    public static List getAllImplementationClassNames(Class cls) {
+//        if (cls == null) {
+//            throw new IllegalArgumentException("The class must not be null");
+//        }
+//        // TODO Use JavaWorld tip for searching the classpath
+//        return null;
+//    }
+
+    // Convert list
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Given a <code>List</code> of class names, this method converts them into classes.</p>
+     *
+     * <p>A new <code>List</code> is returned. If the class name cannot be found, <code>null</code>
+     * is stored in the <code>List</code>. If the class name in the <code>List</code> is
+     * <code>null</code>, <code>null</code> is stored in the output <code>List</code>.</p>
+     * 
+     * @param classNames  the classNames to change
+     * @return a <code>List</code> of Class objects corresponding to the class names,
+     *  <code>null</code> if null input
+     * @throws ClassCastException if classNames contains a non String entry
+     */
+    public static List convertClassNamesToClasses(List classNames) {
+        if (classNames == null) {
+            return null;
+        }
+        List classes = new ArrayList(classNames.size());
+        for (Iterator it = classNames.iterator(); it.hasNext();) {
+            String className = (String) it.next();
+            try {
+                classes.add(Class.forName(className));
+            } catch (Exception ex) {
+                classes.add(null);
+            }
+        }
+        return classes;
+    }
+    
+    /**
+     * <p>Given a <code>List</code> of <code>Class</code> objects, this method converts
+     * them into class names.</p>
+     *
+     * <p>A new <code>List</code> is returned. <code>null</code> objects will be copied into
+     * the returned list as <code>null</code>.</p>
+     * 
+     * @param classes  the classes to change
+     * @return a <code>List</code> of class names corresponding to the Class objects,
+     *  <code>null</code> if null input
+     * @throws ClassCastException if <code>classes</code> contains a non-<code>Class</code> entry
+     */
+    public static List convertClassesToClassNames(List classes) {
+        if (classes == null) {
+            return null;
+        }
+        List classNames = new ArrayList(classes.size());
+        for (Iterator it = classes.iterator(); it.hasNext();) {
+            Class cls = (Class) it.next();
+            if (cls == null) {
+                classNames.add(null);
+            } else {
+                classNames.add(cls.getName());
+            }
+        }
+        return classNames;
+    }
+    
+    // Is assignable
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
+     *
+     * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
+     * Class pair in the input arrays. It can be used to check if a set of arguments
+     * (the first parameter) are suitably compatible with a set of method parameter types
+     * (the second parameter).</p>
+     *
+     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
+     * method takes into account widenings of primitive classes and
+     * <code>null</code>s.</p>
+     *
+     * <p>Primitive widenings allow an int to be assigned to a <code>long</code>,
+     * <code>float</code> or <code>double</code>. This method returns the correct
+     * result for these cases.</p>
+     *
+     * <p><code>Null</code> may be assigned to any reference type. This method will
+     * return <code>true</code> if <code>null</code> is passed in and the toClass is
+     * non-primitive.</p>
+     *
+     * <p>Specifically, this method tests whether the type represented by the
+     * specified <code>Class</code> parameter can be converted to the type
+     * represented by this <code>Class</code> object via an identity conversion
+     * widening primitive or widening reference conversion. See 
+     * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
+     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
+     *
+     * @param classArray  the array of Classes to check, may be <code>null</code>
+     * @param toClassArray  the array of Classes to try to assign into, may be <code>null</code>
+     * @return <code>true</code> if assignment possible
+     */
+    public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
+        if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
+            return false;
+        }
+        if (classArray == null) {
+            classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
+        }
+        if (toClassArray == null) {
+            toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
+        }
+        for (int i = 0; i < classArray.length; i++) {
+            if (isAssignable(classArray[i], toClassArray[i]) == false) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * <p>Checks if one <code>Class</code> can be assigned to a variable of
+     * another <code>Class</code>.</p>
+     *
+     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
+     * this method takes into account widenings of primitive classes and
+     * <code>null</code>s.</p>
+     *
+     * <p>Primitive widenings allow an int to be assigned to a long, float or
+     * double. This method returns the correct result for these cases.</p>
+     *
+     * <p><code>Null</code> may be assigned to any reference type. This method
+     * will return <code>true</code> if <code>null</code> is passed in and the
+     * toClass is non-primitive.</p>
+     *
+     * <p>Specifically, this method tests whether the type represented by the
+     * specified <code>Class</code> parameter can be converted to the type
+     * represented by this <code>Class</code> object via an identity conversion
+     * widening primitive or widening reference conversion. See 
+     * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
+     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
+     *
+     * @param cls  the Class to check, may be null
+     * @param toClass  the Class to try to assign into, returns false if null
+     * @return <code>true</code> if assignment possible
+     */
+    public static boolean isAssignable(Class cls, Class toClass) {
+        if (toClass == null) {
+            return false;
+        }
+        // have to check for null, as isAssignableFrom doesn't
+        if (cls == null) {
+            return !(toClass.isPrimitive());
+        }
+        if (cls.equals(toClass)) {
+            return true;
+        }
+        if (cls.isPrimitive()) {
+            if (toClass.isPrimitive() == false) {
+                return false;
+            }
+            if (Integer.TYPE.equals(cls)) {
+                return Long.TYPE.equals(toClass) 
+                    || Float.TYPE.equals(toClass) 
+                    || Double.TYPE.equals(toClass);
+            }
+            if (Long.TYPE.equals(cls)) {
+                return Float.TYPE.equals(toClass) 
+                    || Double.TYPE.equals(toClass);
+            }
+            if (Boolean.TYPE.equals(cls)) {
+                return false;
+            }
+            if (Double.TYPE.equals(cls)) {
+                return false;
+            }
+            if (Float.TYPE.equals(cls)) {
+                return Double.TYPE.equals(toClass);
+            }
+            if (Character.TYPE.equals(cls)) {
+                return Integer.TYPE.equals(toClass) 
+                    || Long.TYPE.equals(toClass) 
+                    || Float.TYPE.equals(toClass) 
+                    || Double.TYPE.equals(toClass);
+            }
+            if (Short.TYPE.equals(cls)) {
+                return Integer.TYPE.equals(toClass) 
+                    || Long.TYPE.equals(toClass) 
+                    || Float.TYPE.equals(toClass) 
+                    || Double.TYPE.equals(toClass);
+            }
+            if (Byte.TYPE.equals(cls)) {
+                return Short.TYPE.equals(toClass) 
+                    || Integer.TYPE.equals(toClass) 
+                    || Long.TYPE.equals(toClass) 
+                    || Float.TYPE.equals(toClass) 
+                    || Double.TYPE.equals(toClass);
+            }
+            // should never get here
+            return false;
+        }
+        return toClass.isAssignableFrom(cls);
+    }
+    
+    /**
+     * <p>Converts the specified primitive Class object to its corresponding
+     * wrapper Class object.</p>
+     *
+     * @param cls  the class to convert, may be null
+     * @return the wrapper class for <code>cls</code> or <code>cls</code> if
+     * <code>cls</code> is not a primitive. <code>null</code> if null input.
+     */
+    public static Class primitiveToWrapper(Class cls) {
+        Class convertedClass = cls;
+        if (cls != null && cls.isPrimitive()) {
+            convertedClass = (Class) primitiveWrapperMap.get(cls);
+        }   
+        return convertedClass;
+    }
+
+    /**
+     * <p>Converts the specified array of primitive Class objects to an array of 
+     * its corresponding wrapper Class objects.</p>
+     *
+     * @param classes  the class array to convert, may be null or empty
+     * @return an array which contains for each given class, the wrapper class or 
+     * the original class if class is not a primitive. <code>null</code> if null input. 
+     * Empty array if an empty array passed in.
+     */
+    public static Class[] primitivesToWrappers(Class[] classes) {
+        if (classes == null) {
+            return null;
+        }
+        
+        if (classes.length == 0) {
+            return ArrayUtils.EMPTY_CLASS_ARRAY;
+        }
+        
+        Class[] convertedClasses = new Class[classes.length];
+        for (int i=0; i < classes.length; i++) {
+            convertedClasses[i] = primitiveToWrapper( classes[i] );
+        }
+        return convertedClasses;
+    }
+    
+    // Inner class
+    // ----------------------------------------------------------------------
+    /**
+     * <p>Is the specified class an inner class or static nested class.</p>
+     * 
+     * @param cls  the class to check, may be null
+     * @return <code>true</code> if the class is an inner or static nested class,
+     *  false if not or <code>null</code>
+     */
+    public static boolean isInnerClass(Class cls) {
+        if (cls == null) {
+            return false;
+        }
+        return (cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0);
+    }
+    
+    //-----------------------------------------------------------------------
+    /**
+     * Compares two <code>Class</code>s by name.
+     */
+    private static class ClassNameComparator implements Comparator {
+        /**
+         * Compares two <code>Class</code>s by name.
+         * 
+         * @throws ClassCastException
+         *                  If <code>o1</code> or <code>o2</code> are not <code>Class</code>
+         *                  instances.
+         */
+        public int compare(Object o1, Object o2) {
+            Class class1 = (Class) o1;
+            Class class2 = (Class) o2;
+            if (class1 == null) {
+                return class2 == null ? 0 : -1;
+            }
+            if (class2 == null) {
+                return 1;
+            }
+            return class1.getName().compareTo(class2.getName());
+        }
+    }
+    
+    /**
+     * Compares two <code>Class</code>s by name.
+     */
+    public static final Comparator CLASS_NAME_COMPARATOR = new ClassNameComparator();
+
+    /**
+     * Compares two <code>Package</code>s by name.
+     */
+    private static class PackageNameComparator implements Comparator {
+
+        /**
+         * Compares two <code>Package</code>s by name.
+         * 
+         * @throws ClassCastException
+         *                  If <code>o1</code> or <code>o2</code> are not <code>Package</code>
+         *                  instances.
+         */
+        public int compare(Object o1, Object o2) {
+            Package package1 = (Package) o1;
+            Package package2 = (Package) o2;
+            if (package1 == null) {
+                return package2 == null ? 0 : -1;
+            }
+            if (package2 == null) {
+                return 1;
+            }
+            return package1.getName().compareTo(package2.getName());
+        }        
+    }
+    
+    /**
+     * Compares two <code>Package</code>s by name.
+     */
+    public static final Comparator PACKAGE_NAME_COMPARATOR = new PackageNameComparator();
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Enum.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Enum.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>Abstract superclass for type-safe enums.</p>
+ *
+ * <p>One feature of the C programming language lacking in Java is enumerations. The
+ * C implementation based on ints was poor and open to abuse. The original Java
+ * recommendation and most of the JDK also uses int constants. It has been recognised
+ * however that a more robust type-safe class-based solution can be designed. This
+ * class follows the basic Java type-safe enumeration pattern.</p>
+ *
+ * <p><em>NOTE:</em>Due to the way in which Java ClassLoaders work, comparing
+ * Enum objects should always be done using <code>equals()</code>, not <code>==</code>.
+ * The equals() method will try == first so in most cases the effect is the same.</p>
+ * 
+ * <p>Of course, if you actually want (or don't mind) Enums in different class
+ * loaders being non-equal, then you can use <code>==</code>.</p>
+ * 
+ * <h4>Simple Enums</h4>
+ *
+ * <p>To use this class, it must be subclassed. For example:</p>
+ *
+ * <pre>
+ * public final class ColorEnum extends Enum {
+ *   public static final ColorEnum RED = new ColorEnum("Red");
+ *   public static final ColorEnum GREEN = new ColorEnum("Green");
+ *   public static final ColorEnum BLUE = new ColorEnum("Blue");
+ *
+ *   private ColorEnum(String color) {
+ *     super(color);
+ *   }
+ * 
+ *   public static ColorEnum getEnum(String color) {
+ *     return (ColorEnum) getEnum(ColorEnum.class, color);
+ *   }
+ * 
+ *   public static Map getEnumMap() {
+ *     return getEnumMap(ColorEnum.class);
+ *   }
+ * 
+ *   public static List getEnumList() {
+ *     return getEnumList(ColorEnum.class);
+ *   }
+ * 
+ *   public static Iterator iterator() {
+ *     return iterator(ColorEnum.class);
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>As shown, each enum has a name. This can be accessed using <code>getName</code>.</p>
+ *
+ * <p>The <code>getEnum</code> and <code>iterator</code> methods are recommended.
+ * Unfortunately, Java restrictions require these to be coded as shown in each subclass.
+ * An alternative choice is to use the {@link EnumUtils} class.</p>
+ * 
+ * <h4>Subclassed Enums</h4>
+ * <p>A hierarchy of Enum classes can be built. In this case, the superclass is
+ * unaffected by the addition of subclasses (as per normal Java). The subclasses
+ * may add additional Enum constants <em>of the type of the superclass</em>. The
+ * query methods on the subclass will return all of the Enum constants from the
+ * superclass and subclass.</p>
+ *
+ * <pre>
+ * public final class ExtraColorEnum extends ColorEnum {
+ *   // NOTE: Color enum declared above is final, change that to get this
+ *   // example to compile.
+ *   public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
+ *
+ *   private ExtraColorEnum(String color) {
+ *     super(color);
+ *   }
+ * 
+ *   public static ColorEnum getEnum(String color) {
+ *     return (ColorEnum) getEnum(ExtraColorEnum.class, color);
+ *   }
+ * 
+ *   public static Map getEnumMap() {
+ *     return getEnumMap(ExtraColorEnum.class);
+ *   }
+ * 
+ *   public static List getEnumList() {
+ *     return getEnumList(ExtraColorEnum.class);
+ *   }
+ * 
+ *   public static Iterator iterator() {
+ *     return iterator(ExtraColorEnum.class);
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>This example will return RED, GREEN, BLUE, YELLOW from the List and iterator
+ * methods in that order. The RED, GREEN and BLUE instances will be the same (==) 
+ * as those from the superclass ColorEnum. Note that YELLOW is declared as a
+ * ColorEnum and not an ExtraColorEnum.</p>
+ * 
+ * <h4>Functional Enums</h4>
+ *
+ * <p>The enums can have functionality by defining subclasses and
+ * overriding the <code>getEnumClass()</code> method:</p>
+ * 
+ * <pre>
+ *   public static final OperationEnum PLUS = new PlusOperation();
+ *   private static final class PlusOperation extends OperationEnum {
+ *     private PlusOperation() {
+ *       super("Plus");
+ *     }
+ *     public int eval(int a, int b) {
+ *       return (a + b);
+ *     }
+ *   }
+ *   public static final OperationEnum MINUS = new MinusOperation();
+ *   private static final class MinusOperation extends OperationEnum {
+ *     private MinusOperation() {
+ *       super("Minus");
+ *     }
+ *     public int eval(int a, int b) {
+ *       return (a - b);
+ *     }
+ *   }
+ *
+ *   private OperationEnum(String color) {
+ *     super(color);
+ *   }
+ * 
+ *   public final Class getEnumClass() {     // NOTE: new method!
+ *     return OperationEnum.class;
+ *   }
+ *
+ *   public abstract double eval(double a, double b);
+ * 
+ *   public static OperationEnum getEnum(String name) {
+ *     return (OperationEnum) getEnum(OperationEnum.class, name);
+ *   }
+ * 
+ *   public static Map getEnumMap() {
+ *     return getEnumMap(OperationEnum.class);
+ *   }
+ * 
+ *   public static List getEnumList() {
+ *     return getEnumList(OperationEnum.class);
+ *   }
+ * 
+ *   public static Iterator iterator() {
+ *     return iterator(OperationEnum.class);
+ *   }
+ * }
+ * </pre>
+ * <p>The code above will work on JDK 1.2. If JDK1.3 and later is used,
+ * the subclasses may be defined as anonymous.</p>
+ * 
+ * <h4>Nested class Enums</h4>
+ *
+ * <p>Care must be taken with class loading when defining a static nested class
+ * for enums. The static nested class can be loaded without the surrounding outer
+ * class being loaded. This can result in an empty list/map/iterator being returned.
+ * One solution is to define a static block that references the outer class where
+ * the constants are defined. For example:</p>
+ *
+ * <pre>
+ * public final class Outer {
+ *   public static final BWEnum BLACK = new BWEnum("Black");
+ *   public static final BWEnum WHITE = new BWEnum("White");
+ *
+ *   // static nested enum class
+ *   public static final class BWEnum extends Enum {
+ * 
+ *     static {
+ *       // explicitly reference BWEnum class to force constants to load
+ *       Object obj = Outer.BLACK;
+ *     }
+ * 
+ *     // ... other methods omitted
+ *   }
+ * }
+ * </pre>
+ * 
+ * <p>Although the above solves the problem, it is not recommended. The best solution
+ * is to define the constants in the enum class, and hold references in the outer class:
+ *
+ * <pre>
+ * public final class Outer {
+ *   public static final BWEnum BLACK = BWEnum.BLACK;
+ *   public static final BWEnum WHITE = BWEnum.WHITE;
+ *
+ *   // static nested enum class
+ *   public static final class BWEnum extends Enum {
+ *     // only define constants in enum classes - private if desired
+ *     private static final BWEnum BLACK = new BWEnum("Black");
+ *     private static final BWEnum WHITE = new BWEnum("White");
+ * 
+ *     // ... other methods omitted
+ *   }
+ * }
+ * </pre>
+ * 
+ * <p>For more details, see the 'Nested' test cases.
+ * 
+ * @author Apache Avalon project
+ * @author Stephen Colebourne
+ * @author Chris Webb
+ * @author Mike Bowler
+ * @since 1.0
+ * @version $Id: Enum.java,v 1.28 2004/02/23 04:34:20 ggregory Exp $
+ */
+public abstract class Enum implements Comparable, Serializable {
+
+    /** Lang version 1.0.1 serial compatibility */
+    private static final long serialVersionUID = -487045951170455942L;
+    
+    // After discussion, the default size for HashMaps is used, as the
+    // sizing algorithm changes across the JDK versions
+    /**
+     * An empty <code>Map</code>, as JDK1.2 didn't have an empty map.
+     */
+    private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(0));
+    
+    /**
+     * <code>Map</code>, key of class name, value of <code>Entry</code>.
+     */
+    private static final Map cEnumClasses = new HashMap();
+    
+    /**
+     * The string representation of the Enum.
+     */
+    private final String iName;
+    
+    /**
+     * The hashcode representation of the Enum.
+     */
+    private transient final int iHashCode;
+    
+    /**
+     * The toString representation of the Enum.
+     * @since 2.0
+     */
+    protected transient String iToString = null;
+
+    /**
+     * <p>Enable the iterator to retain the source code order.</p>
+     */
+    private static class Entry {
+        /**
+         * Map of Enum name to Enum.
+         */
+        final Map map = new HashMap();
+        /**
+         * Map of Enum name to Enum.
+         */
+        final Map unmodifiableMap = Collections.unmodifiableMap(map);
+        /**
+         * List of Enums in source code order.
+         */
+        final List list = new ArrayList(25);
+        /**
+         * Map of Enum name to Enum.
+         */
+        final List unmodifiableList = Collections.unmodifiableList(list);
+
+        /**
+         * <p>Restrictive constructor.</p>
+         */
+        private Entry() {
+        }
+    }
+
+    /**
+     * <p>Constructor to add a new named item to the enumeration.</p>
+     *
+     * @param name  the name of the enum object,
+     *  must not be empty or <code>null</code>
+     * @throws IllegalArgumentException if the name is <code>null</code>
+     *  or an empty string
+     * @throws IllegalArgumentException if the getEnumClass() method returns
+     *  a null or invalid Class
+     */
+    protected Enum(String name) {
+        super();
+        init(name);
+        iName = name;
+        iHashCode = 7 + getEnumClass().hashCode() + 3 * name.hashCode();
+        // cannot create toString here as subclasses may want to include other data
+    }
+
+    private static boolean isEmpty(String str) {
+        return (str == null || str.length() == 0);
+    }
+
+    /**
+     * Initializes the enumeration.
+     * 
+     * @param name  the enum name
+     * @throws IllegalArgumentException if the name is null or empty or duplicate
+     * @throws IllegalArgumentException if the enumClass is null or invalid
+     */
+    private void init(String name) {
+        if (isEmpty(name)) {
+            throw new IllegalArgumentException("The Enum name must not be empty or null");
+        }
+        
+        Class enumClass = getEnumClass();
+        if (enumClass == null) {
+            throw new IllegalArgumentException("getEnumClass() must not be null");
+        }
+        Class cls = getClass();
+        boolean ok = false;
+        while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
+            if (cls == enumClass) {
+                ok = true;
+                break;
+            }
+            cls = cls.getSuperclass();
+        }
+        if (ok == false) {
+            throw new IllegalArgumentException("getEnumClass() must return a superclass of this class");
+        }
+        
+        // create entry
+        Entry entry = (Entry) cEnumClasses.get(enumClass);
+        if (entry == null) {
+            entry = createEntry(enumClass);
+            cEnumClasses.put(enumClass, entry);
+        }
+        if (entry.map.containsKey(name)) {
+            throw new IllegalArgumentException("The Enum name must be unique, '" + name + "' has already been added");
+        }
+        entry.map.put(name, this);
+        entry.list.add(this);
+    }
+
+    /**
+     * <p>Handle the deserialization of the class to ensure that multiple
+     * copies are not wastefully created, or illegal enum types created.</p>
+     *
+     * @return the resolved object
+     */
+    protected Object readResolve() {
+        Entry entry = (Entry) cEnumClasses.get(getEnumClass());
+        if (entry == null) {
+            return null;
+        }
+        return (Enum) entry.map.get(getName());
+    }
+    
+    //--------------------------------------------------------------------------------
+
+    /**
+     * <p>Gets an <code>Enum</code> object by class and name.</p>
+     * 
+     * @param enumClass  the class of the Enum to get, must not
+     *  be <code>null</code>
+     * @param name  the name of the <code>Enum</code> to get,
+     *  may be <code>null</code>
+     * @return the enum object, or null if the enum does not exist
+     * @throws IllegalArgumentException if the enum class
+     *  is <code>null</code>
+     */
+    protected static Enum getEnum(Class enumClass, String name) {
+        Entry entry = getEntry(enumClass);
+        if (entry == null) {
+            return null;
+        }
+        return (Enum) entry.map.get(name);
+    }
+
+    /**
+     * <p>Gets the <code>Map</code> of <code>Enum</code> objects by
+     * name using the <code>Enum</code> class.</p>
+     *
+     * <p>If the requested class has no enum objects an empty
+     * <code>Map</code> is returned.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get,
+     *  must not be <code>null</code>
+     * @return the enum object Map
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass of Enum
+     */
+    protected static Map getEnumMap(Class enumClass) {
+        Entry entry = getEntry(enumClass);
+        if (entry == null) {
+            return EMPTY_MAP;
+        }
+        return entry.unmodifiableMap;
+    }
+
+    /**
+     * <p>Gets the <code>List</code> of <code>Enum</code> objects using the
+     * <code>Enum</code> class.</p>
+     *
+     * <p>The list is in the order that the objects were created (source code order).
+     * If the requested class has no enum objects an empty <code>List</code> is
+     * returned.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get,
+     *  must not be <code>null</code>
+     * @return the enum object Map
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass of Enum
+     */
+    protected static List getEnumList(Class enumClass) {
+        Entry entry = getEntry(enumClass);
+        if (entry == null) {
+            return Collections.EMPTY_LIST;
+        }
+        return entry.unmodifiableList;
+    }
+
+    /**
+     * <p>Gets an <code>Iterator</code> over the <code>Enum</code> objects in
+     * an <code>Enum</code> class.</p>
+     *
+     * <p>The <code>Iterator</code> is in the order that the objects were
+     * created (source code order). If the requested class has no enum
+     * objects an empty <code>Iterator</code> is returned.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get,
+     *  must not be <code>null</code>
+     * @return an iterator of the Enum objects
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass of Enum
+     */
+    protected static Iterator iterator(Class enumClass) {
+        return Enum.getEnumList(enumClass).iterator();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Gets an <code>Entry</code> from the map of Enums.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @return the enum entry
+     */
+    private static Entry getEntry(Class enumClass) {
+        if (enumClass == null) {
+            throw new IllegalArgumentException("The Enum Class must not be null");
+        }
+        if (Enum.class.isAssignableFrom(enumClass) == false) {
+            throw new IllegalArgumentException("The Class must be a subclass of Enum");
+        }
+        Entry entry = (Entry) cEnumClasses.get(enumClass);
+        return entry;
+    }
+    
+    /**
+     * <p>Creates an <code>Entry</code> for storing the Enums.</p>
+     *
+     * <p>This accounts for subclassed Enums.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @return the enum entry
+     */
+    private static Entry createEntry(Class enumClass) {
+        Entry entry = new Entry();
+        Class cls = enumClass.getSuperclass();
+        while (cls != null && cls != Enum.class && cls != ValuedEnum.class) {
+            Entry loopEntry = (Entry) cEnumClasses.get(cls);
+            if (loopEntry != null) {
+                entry.list.addAll(loopEntry.list);
+                entry.map.putAll(loopEntry.map);
+                break;  // stop here, as this will already have had superclasses added
+            }
+            cls = cls.getSuperclass();
+        }
+        return entry;
+    }
+    
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Retrieve the name of this Enum item, set in the constructor.</p>
+     * 
+     * @return the <code>String</code> name of this Enum item
+     */
+    public final String getName() {
+        return iName;
+    }
+
+    /**
+     * <p>Retrieves the Class of this Enum item, set in the constructor.</p>
+     * 
+     * <p>This is normally the same as <code>getClass()</code>, but for
+     * advanced Enums may be different. If overridden, it must return a
+     * constant value.</p>
+     * 
+     * @return the <code>Class</code> of the enum
+     * @since 2.0
+     */
+    public Class getEnumClass() {
+        return getClass();
+    }
+
+    /**
+     * <p>Tests for equality.</p>
+     *
+     * <p>Two Enum objects are considered equal
+     * if they have the same class names and the same names.
+     * Identity is tested for first, so this method usually runs fast.</p>
+     * 
+     * <p>If the parameter is in a different class loader than this instance,
+     * reflection is used to compare the names.</p>
+     *
+     * @param other  the other object to compare for equality
+     * @return <code>true</code> if the Enums are equal
+     */
+    public final boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        } else if (other == null) {
+            return false;
+        } else if (other.getClass() == this.getClass()) {
+            // Ok to do a class cast to Enum here since the test above
+            // guarantee both
+            // classes are in the same class loader.
+            return iName.equals(((Enum) other).iName);
+        } else {
+            // This and other are in different class loaders, we must use reflection.
+            try {
+                Method mth = other.getClass().getMethod("getName", null);
+                String name = (String) mth.invoke(other, null);
+                return iName.equals(name);
+            } catch (NoSuchMethodException e) {
+                // ignore - should never happen
+            } catch (IllegalAccessException e) {
+                // ignore - should never happen
+            } catch (InvocationTargetException e) {
+                // ignore - should never happen
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * <p>Returns a suitable hashCode for the enumeration.</p>
+     *
+     * @return a hashcode based on the name
+     */
+    public final int hashCode() {
+        return iHashCode;
+    }
+
+    /**
+     * <p>Tests for order.</p>
+     *
+     * <p>The default ordering is alphabetic by name, but this
+     * can be overridden by subclasses.</p>
+     * 
+     * @see java.lang.Comparable#compareTo(Object)
+     * @param other  the other object to compare to
+     * @return -ve if this is less than the other object, +ve if greater
+     *  than, <code>0</code> of equal
+     * @throws ClassCastException if other is not an Enum
+     * @throws NullPointerException if other is <code>null</code>
+     */
+    public int compareTo(Object other) {
+        if (other == this) {
+            return 0;
+        }
+        return iName.compareTo(((Enum) other).iName);
+    }
+
+    /**
+     * <p>Human readable description of this Enum item.</p>
+     * 
+     * @return String in the form <code>type[name]</code>, for example:
+     * <code>Color[Red]</code>. Note that the package name is stripped from
+     * the type name.
+     */
+    public String toString() {
+        if (iToString == null) {
+            String shortName = ClassUtils.getShortClassName(getEnumClass());
+            iToString = shortName + "[" + getName() + "]";
+        }
+        return iToString;
+    }
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EnumUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EnumUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>Utility class for accessing and manipulating {@link Enum}s.</p>
+ *
+ * @see Enum
+ * @see ValuedEnum
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @since 1.0
+ * @version $Id: EnumUtils.java,v 1.12 2004/02/23 04:34:20 ggregory Exp $
+ */
+public class EnumUtils {
+
+    /**
+     * Public constructor. This class should not normally be instantiated.
+     * @since 2.0
+     */
+    public EnumUtils() {
+    }
+
+    /**
+     * <p>Gets an <code>Enum</code> object by class and name.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @param name  the name of the Enum to get, may be <code>null</code>
+     * @return the enum object
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     */
+    public static Enum getEnum(Class enumClass, String name) {
+        return Enum.getEnum(enumClass, name);
+    }
+
+    /**
+     * <p>Gets a <code>ValuedEnum</code> object by class and value.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @param value  the value of the <code>Enum</code> to get
+     * @return the enum object, or null if the enum does not exist
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     */
+    public static ValuedEnum getEnum(Class enumClass, int value) {
+        return (ValuedEnum) ValuedEnum.getEnum(enumClass, value);
+    }
+
+    /**
+     * <p>Gets the <code>Map</code> of <code>Enum</code> objects by
+     * name using the <code>Enum</code> class.</p>
+     *
+     * <p>If the requested class has no enum objects an empty
+     * <code>Map</code> is returned. The <code>Map</code> is unmodifiable.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @return the enum object Map
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass
+     *  of <code>Enum</code>
+     */
+    public static Map getEnumMap(Class enumClass) {
+        return Enum.getEnumMap(enumClass);
+    }
+
+    /**
+     * <p>Gets the <code>List</code> of <code>Enum</code> objects using
+     * the <code>Enum</code> class.</p>
+     *
+     * <p>The list is in the order that the objects were created
+     * (source code order).</p>
+     *
+     * <p>If the requested class has no enum objects an empty
+     * <code>List</code> is returned. The <code>List</code> is unmodifiable.</p>
+     * 
+     * @param enumClass  the class of the Enum to get
+     * @return the enum object Map
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass
+     *  of <code>Enum</code>
+     */
+    public static List getEnumList(Class enumClass) {
+        return Enum.getEnumList(enumClass);
+    }
+
+    /**
+     * <p>Gets an <code>Iterator</code> over the <code>Enum</code> objects
+     * in an <code>Enum</code> class.</p>
+     *
+     * <p>The iterator is in the order that the objects were created
+     * (source code order).</p>
+     *
+     * <p>If the requested class has no enum objects an empty
+     * <code>Iterator</code> is returned. The <code>Iterator</code>
+     * is unmodifiable.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @return an <code>Iterator</code> of the <code>Enum</code> objects
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     * @throws IllegalArgumentException if the enum class is not a subclass of <code>Enum</code>
+     */
+    public static Iterator iterator(Class enumClass) {
+        return Enum.getEnumList(enumClass).iterator();
+    }
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EqualsBuilder.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/EqualsBuilder.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
+ *
+ * <p> This class provides methods to build a good equals method for any
+ * class. It follows rules laid out in
+ * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
+ * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
+ * <code>floats</code>, and arrays can be tricky. Also, making sure that
+ * <code>equals()</code> and <code>hashCode()</code> are consistent can be
+ * difficult.</p>
+ *
+ * <p>Two Objects that compare as equals must generate the same hash code,
+ * but two Objects with the same hash code do not have to be equal.</p>
+ *
+ * <p>All relevant fields should be included in the calculation of equals.
+ * Derived fields may be ignored. In particular, any field used in
+ * generating a hash code must be used in the equals method, and vice
+ * versa.</p>
+ *
+ * <p>Typical use for the code is as follows:</p>
+ * <pre>
+ * public boolean equals(Object o) {
+ *   if ( !(o instanceof MyClass) ) {
+ *    return false;
+ *   }
+ *  MyClass rhs = (MyClass) o;
+ *  return new EqualsBuilder()
+ *                 .appendSuper(super.equals(o))
+ *                 .append(field1, rhs.field1)
+ *                 .append(field2, rhs.field2)
+ *                 .append(field3, rhs.field3)
+ *                 .isEquals();
+ *  }
+ * </pre>
+ *
+ * <p> Alternatively, there is a method that uses reflection to determine
+ * the fields to test. Because these fields are usually private, the method,
+ * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
+ * change the visibility of the fields. This will fail under a security
+ * manager, unless the appropriate permissions are set up correctly. It is
+ * also slower than testing explicitly.</p>
+ *
+ * <p> A typical invocation for this method would look like:</p>
+ * <pre>
+ * public boolean equals(Object o) {
+ *   return EqualsBuilder.reflectionEquals(this, o);
+ * }
+ * </pre>
+ *
+ * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Pete Gieser
+ * @author Arun Mammen Thomas
+ * @since 1.0
+ * @version $Id: EqualsBuilder.java,v 1.26 2004/08/26 05:46:45 ggregory Exp $
+ */
+public class EqualsBuilder {
+    
+    /**
+     * If the fields tested are equals.
+     * The default value is <code>true</code>.
+     */
+    private boolean isEquals = true;
+
+    /**
+     * <p>Constructor for EqualsBuilder.</p>
+     *
+     * <p>Starts off assuming that equals is <code>true</code>.</p>
+     * @see Object#equals(Object)
+     */
+    public EqualsBuilder() {
+        // do nothing for now.
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>This method uses reflection to determine if the two <code>Object</code>s
+     * are equal.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is also
+     * not as efficient as testing explicitly.</p>
+     *
+     * <p>Transient members will be not be tested, as they are likely derived
+     * fields, and not part of the value of the Object.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * @param lhs  <code>this</code> object
+     * @param rhs  the other object
+     * @return <code>true</code> if the two Objects have tested equals.
+     */
+    public static boolean reflectionEquals(Object lhs, Object rhs) {
+        return reflectionEquals(lhs, rhs, false, null);
+    }
+
+    /**
+     * <p>This method uses reflection to determine if the two <code>Object</code>s
+     * are equal.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is also
+     * not as efficient as testing explicitly.</p>
+     *
+     * <p>If the TestTransients parameter is set to <code>true</code>, transient
+     * members will be tested, otherwise they are ignored, as they are likely
+     * derived fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * @param lhs  <code>this</code> object
+     * @param rhs  the other object
+     * @param testTransients  whether to include transient fields
+     * @return <code>true</code> if the two Objects have tested equals.
+     */
+    public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
+        return reflectionEquals(lhs, rhs, testTransients, null);
+    }
+
+    /**
+     * <p>This method uses reflection to determine if the two <code>Object</code>s
+     * are equal.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is also
+     * not as efficient as testing explicitly.</p>
+     *
+     * <p>If the testTransients parameter is set to <code>true</code>, transient
+     * members will be tested, otherwise they are ignored, as they are likely
+     * derived fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be included. Superclass fields will be appended
+     * up to and including the specified superclass. A null superclass is treated
+     * as java.lang.Object.</p>
+     *
+     * @param lhs  <code>this</code> object
+     * @param rhs  the other object
+     * @param testTransients  whether to include transient fields
+     * @param reflectUpToClass  the superclass to reflect up to (inclusive),
+     *  may be <code>null</code>
+     * @return <code>true</code> if the two Objects have tested equals.
+     * @since 2.0
+     */
+    public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) {
+        if (lhs == rhs) {
+            return true;
+        }
+        if (lhs == null || rhs == null) {
+            return false;
+        }
+        // Find the leaf class since there may be transients in the leaf 
+        // class or in classes between the leaf and root.
+        // If we are not testing transients or a subclass has no ivars, 
+        // then a subclass can test equals to a superclass.
+        Class lhsClass = lhs.getClass();
+        Class rhsClass = rhs.getClass();
+        Class testClass;
+        if (lhsClass.isInstance(rhs)) {
+            testClass = lhsClass;
+            if (!rhsClass.isInstance(lhs)) {
+                // rhsClass is a subclass of lhsClass
+                testClass = rhsClass;
+            }
+        } else if (rhsClass.isInstance(lhs)) {
+            testClass = rhsClass;
+            if (!lhsClass.isInstance(rhs)) {
+                // lhsClass is a subclass of rhsClass
+                testClass = lhsClass;
+            }
+        } else {
+            // The two classes are not related.
+            return false;
+        }
+        EqualsBuilder equalsBuilder = new EqualsBuilder();
+        try {
+            reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
+            while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
+                testClass = testClass.getSuperclass();
+                reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients);
+            }
+        } catch (IllegalArgumentException e) {
+            // In this case, we tried to test a subclass vs. a superclass and
+            // the subclass has ivars or the ivars are transient and 
+            // we are testing transients.
+            // If a subclass has ivars that we are trying to test them, we get an
+            // exception and we know that the objects are not equal.
+            return false;
+        }
+        return equalsBuilder.isEquals();
+    }
+
+    /**
+     * <p>Appends the fields and values defined by the given object of the
+     * given Class.</p>
+     * 
+     * @param lhs  the left hand object
+     * @param rhs  the right hand object
+     * @param clazz  the class to append details of
+     * @param builder  the builder to append to
+     * @param useTransients  whether to test transient fields
+     */
+    private static void reflectionAppend(
+        Object lhs,
+        Object rhs,
+        Class clazz,
+        EqualsBuilder builder,
+        boolean useTransients) {
+        Field[] fields = clazz.getDeclaredFields();
+        AccessibleObject.setAccessible(fields, true);
+        for (int i = 0; i < fields.length && builder.isEquals; i++) {
+            Field f = fields[i];
+            if ((f.getName().indexOf('$') == -1)
+                && (useTransients || !Modifier.isTransient(f.getModifiers()))
+                && (!Modifier.isStatic(f.getModifiers()))) {
+                try {
+                    builder.append(f.get(lhs), f.get(rhs));
+                } catch (IllegalAccessException e) {
+                    //this can't happen. Would get a Security exception instead
+                    //throw a runtime exception in case the impossible happens.
+                    throw new InternalError("Unexpected IllegalAccessException");
+                }
+            }
+        }
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
+     *
+     * @param superEquals  the result of calling <code>super.equals()</code>
+     * @return EqualsBuilder - used to chain calls.
+     * @since 2.0
+     */
+    public EqualsBuilder appendSuper(boolean superEquals) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = superEquals;
+        return this;
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>Test if two <code>Object</code>s are equal using their
+     * <code>equals</code> method.</p>
+     *
+     * @param lhs  the left hand object
+     * @param rhs  the right hand object
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(Object lhs, Object rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        Class lhsClass = lhs.getClass();
+        if (!lhsClass.isArray()) {
+            // The simple case, not an array, just test the element
+            isEquals = lhs.equals(rhs);
+        } else if (lhs.getClass() != rhs.getClass()) {
+            // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] 
+            this.setEquals(false);
+        }
+        // 'Switch' on type of array, to dispatch to the correct handler
+        // This handles multi dimensional arrays of the same depth
+        else if (lhs instanceof long[]) {
+            append((long[]) lhs, (long[]) rhs);
+        } else if (lhs instanceof int[]) {
+            append((int[]) lhs, (int[]) rhs);
+        } else if (lhs instanceof short[]) {
+            append((short[]) lhs, (short[]) rhs);
+        } else if (lhs instanceof char[]) {
+            append((char[]) lhs, (char[]) rhs);
+        } else if (lhs instanceof byte[]) {
+            append((byte[]) lhs, (byte[]) rhs);
+        } else if (lhs instanceof double[]) {
+            append((double[]) lhs, (double[]) rhs);
+        } else if (lhs instanceof float[]) {
+            append((float[]) lhs, (float[]) rhs);
+        } else if (lhs instanceof boolean[]) {
+            append((boolean[]) lhs, (boolean[]) rhs);
+        } else {
+            // Not an array of primitives
+            append((Object[]) lhs, (Object[]) rhs);
+        }
+        return this;
+    }
+
+    /**
+     * <p>
+     * Test if two <code>long</code> s are equal.
+     * </p>
+     * 
+     * @param lhs
+     *                  the left hand <code>long</code>
+     * @param rhs
+     *                  the right hand <code>long</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(long lhs, long rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Test if two <code>int</code>s are equal.</p>
+     *
+     * @param lhs  the left hand <code>int</code>
+     * @param rhs  the right hand <code>int</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(int lhs, int rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Test if two <code>short</code>s are equal.</p>
+     *
+     * @param lhs  the left hand <code>short</code>
+     * @param rhs  the right hand <code>short</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(short lhs, short rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Test if two <code>char</code>s are equal.</p>
+     *
+     * @param lhs  the left hand <code>char</code>
+     * @param rhs  the right hand <code>char</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(char lhs, char rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Test if two <code>byte</code>s are equal.</p>
+     *
+     * @param lhs  the left hand <code>byte</code>
+     * @param rhs  the right hand <code>byte</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(byte lhs, byte rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Test if two <code>double</code>s are equal by testing that the
+     * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
+     *
+     * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
+     *
+     * <p>It is compatible with the hash code generated by
+     * <code>HashCodeBuilder</code>.</p>
+     *
+     * @param lhs  the left hand <code>double</code>
+     * @param rhs  the right hand <code>double</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(double lhs, double rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
+    }
+
+    /**
+     * <p>Test if two <code>float</code>s are equal byt testing that the
+     * pattern of bits returned by doubleToLong are equal.</p>
+     *
+     * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
+     *
+     * <p>It is compatible with the hash code generated by
+     * <code>HashCodeBuilder</code>.</p>
+     *
+     * @param lhs  the left hand <code>float</code>
+     * @param rhs  the right hand <code>float</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(float lhs, float rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
+    }
+
+    /**
+     * <p>Test if two <code>booleans</code>s are equal.</p>
+     *
+     * @param lhs  the left hand <code>boolean</code>
+     * @param rhs  the right hand <code>boolean</code>
+     * @return EqualsBuilder - used to chain calls.
+      */
+    public EqualsBuilder append(boolean lhs, boolean rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        isEquals = (lhs == rhs);
+        return this;
+    }
+
+    /**
+     * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
+     *
+     * <p>This also will be called for the top level of
+     * multi-dimensional, ragged, and multi-typed arrays.</p>
+     *
+     * @param lhs  the left hand <code>Object[]</code>
+     * @param rhs  the right hand <code>Object[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(Object[] lhs, Object[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>long</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(long, long)} is used.</p>
+     *
+     * @param lhs  the left hand <code>long[]</code>
+     * @param rhs  the right hand <code>long[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(long[] lhs, long[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>int</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(int, int)} is used.</p>
+     *
+     * @param lhs  the left hand <code>int[]</code>
+     * @param rhs  the right hand <code>int[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(int[] lhs, int[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>short</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(short, short)} is used.</p>
+     *
+     * @param lhs  the left hand <code>short[]</code>
+     * @param rhs  the right hand <code>short[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(short[] lhs, short[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>char</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(char, char)} is used.</p>
+     *
+     * @param lhs  the left hand <code>char[]</code>
+     * @param rhs  the right hand <code>char[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(char[] lhs, char[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>byte</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(byte, byte)} is used.</p>
+     *
+     * @param lhs  the left hand <code>byte[]</code>
+     * @param rhs  the right hand <code>byte[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(byte[] lhs, byte[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>double</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(double, double)} is used.</p>
+     *
+     * @param lhs  the left hand <code>double[]</code>
+     * @param rhs  the right hand <code>double[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(double[] lhs, double[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>float</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(float, float)} is used.</p>
+     *
+     * @param lhs  the left hand <code>float[]</code>
+     * @param rhs  the right hand <code>float[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(float[] lhs, float[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Deep comparison of array of <code>boolean</code>. Length and all
+     * values are compared.</p>
+     *
+     * <p>The method {@link #append(boolean, boolean)} is used.</p>
+     *
+     * @param lhs  the left hand <code>boolean[]</code>
+     * @param rhs  the right hand <code>boolean[]</code>
+     * @return EqualsBuilder - used to chain calls.
+     */
+    public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
+        if (isEquals == false) {
+            return this;
+        }
+        if (lhs == rhs) {
+            return this;
+        }
+        if (lhs == null || rhs == null) {
+            this.setEquals(false);
+            return this;
+        }
+        if (lhs.length != rhs.length) {
+            this.setEquals(false);
+            return this;
+        }
+        for (int i = 0; i < lhs.length && isEquals; ++i) {
+            append(lhs[i], rhs[i]);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Returns <code>true</code> if the fields that have been checked
+     * are all equal.</p>
+     *
+     * @return boolean
+     */
+    public boolean isEquals() {
+        return this.isEquals;
+    }
+
+    /**
+     * Sets the <code>isEquals</code> value.
+     * 
+     * @param isEquals The value to set.
+     */
+    protected void setEquals(boolean isEquals) {
+        this.isEquals = isEquals;
+    }
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ExceptionUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ExceptionUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,688 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+
+/**
+ * <p>Provides utilities for manipulating and examining 
+ * <code>Throwable</code> objects.</p>
+ *
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author Dmitri Plotnikov
+ * @author Stephen Colebourne
+ * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
+ * @author Pete Gieser
+ * @since 1.0
+ * @version $Id: ExceptionUtils.java,v 1.39 2004/07/04 03:24:57 bayard Exp $
+ */
+public class ExceptionUtils {
+    
+    /**
+     * <p>Used when printing stack frames to denote the start of a
+     * wrapped exception.</p>
+     *
+     * <p>Package private for accessibility by test suite.</p>
+     */
+    static final String WRAPPED_MARKER = " [wrapped] ";
+
+    /**
+     * <p>The names of methods commonly used to access a wrapped exception.</p>
+     */
+    private static String[] CAUSE_METHOD_NAMES = {
+        "getCause",
+        "getNextException",
+        "getTargetException",
+        "getException",
+        "getSourceException",
+        "getRootCause",
+        "getCausedByException",
+        "getNested",
+        "getLinkedException",
+        "getNestedException",
+        "getLinkedCause",
+        "getThrowable",
+    };
+
+    /**
+     * <p>The Method object for JDK1.4 getCause.</p>
+     */
+    private static final Method THROWABLE_CAUSE_METHOD;
+    static {
+        Method getCauseMethod;
+        try {
+            getCauseMethod = Throwable.class.getMethod("getCause", null);
+        } catch (Exception e) {
+            getCauseMethod = null;
+        }
+        THROWABLE_CAUSE_METHOD = getCauseMethod;
+    }
+    
+    /**
+     * <p>Public constructor allows an instance of <code>ExceptionUtils</code>
+     * to be created, although that is not normally necessary.</p>
+     */
+    public ExceptionUtils() {
+    }
+
+    /**
+     * <p>Checks if a String is not empty ("") and not null.</p>
+     *
+     * @param str  the String to check, may be null
+     * @return <code>true</code> if the String is not empty and not null
+     */
+    private static boolean isNotEmpty(String str) {
+        return (str != null && str.length() > 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Adds to the list of method names used in the search for <code>Throwable</code>
+     * objects.</p>
+     * 
+     * @param methodName  the methodName to add to the list, <code>null</code>
+     *  and empty strings are ignored
+     * @since 2.0
+     */
+    public static void addCauseMethodName(String methodName) {
+        if (isNotEmpty(methodName)) {
+            List list = new ArrayList(Arrays.asList(CAUSE_METHOD_NAMES));
+            list.add(methodName);
+            CAUSE_METHOD_NAMES = (String[]) list.toArray(new String[list.size()]);
+        }
+    }
+
+    /**
+     * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
+     * 
+     * <p>The method searches for methods with specific names that return a 
+     * <code>Throwable</code> object. This will pick up most wrapping exceptions,
+     * including those from JDK 1.4, and
+     * The method names can be added to using {@link #addCauseMethodName(String)}.</p>
+     *
+     * <p>The default list searched for are:</p>
+     * <ul>
+     *  <li><code>getCause()</code></li>
+     *  <li><code>getNextException()</code></li>
+     *  <li><code>getTargetException()</code></li>
+     *  <li><code>getException()</code></li>
+     *  <li><code>getSourceException()</code></li>
+     *  <li><code>getRootCause()</code></li>
+     *  <li><code>getCausedByException()</code></li>
+     *  <li><code>getNested()</code></li>
+     * </ul>
+     * 
+     * <p>In the absence of any such method, the object is inspected for a
+     * <code>detail</code> field assignable to a <code>Throwable</code>.</p>
+     * 
+     * <p>If none of the above is found, returns <code>null</code>.</p>
+     *
+     * @param throwable  the throwable to introspect for a cause, may be null
+     * @return the cause of the <code>Throwable</code>,
+     *  <code>null</code> if none found or null throwable input
+     * @since 1.0
+     */
+    public static Throwable getCause(Throwable throwable) {
+        return getCause(throwable, CAUSE_METHOD_NAMES);
+    }
+
+    /**
+     * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
+     * 
+     * <ol>
+     * <li>Try known exception types.</li>
+     * <li>Try the supplied array of method names.</li>
+     * <li>Try the field 'detail'.</li>
+     * </ol>
+     * 
+     * <p>A <code>null</code> set of method names means use the default set.
+     * A <code>null</code> in the set of method names will be ignored.</p>
+     *
+     * @param throwable  the throwable to introspect for a cause, may be null
+     * @param methodNames  the method names, null treated as default set
+     * @return the cause of the <code>Throwable</code>,
+     *  <code>null</code> if none found or null throwable input
+     * @since 1.0
+     */
+    public static Throwable getCause(Throwable throwable, String[] methodNames) {
+        if (throwable == null) {
+            return null;
+        }
+        Throwable cause = getCauseUsingWellKnownTypes(throwable);
+        if (cause == null) {
+            if (methodNames == null) {
+                methodNames = CAUSE_METHOD_NAMES;
+            }
+            for (int i = 0; i < methodNames.length; i++) {
+                String methodName = methodNames[i];
+                if (methodName != null) {
+                    cause = getCauseUsingMethodName(throwable, methodName);
+                    if (cause != null) {
+                        break;
+                    }
+                }
+            }
+
+            if (cause == null) {
+                cause = getCauseUsingFieldName(throwable, "detail");
+            }
+        }
+        return cause;
+    }
+
+    /**
+     * <p>Introspects the <code>Throwable</code> to obtain the root cause.</p>
+     * 
+     * <p>This method walks through the exception chain to the last element,
+     * "root" of the tree, using {@link #getCause(Throwable)}, and
+     * returns that exception.</p>
+     *
+     * @param throwable  the throwable to get the root cause for, may be null
+     * @return the root cause of the <code>Throwable</code>,
+     *  <code>null</code> if none found or null throwable input
+     */
+    public static Throwable getRootCause(Throwable throwable) {
+        Throwable cause = getCause(throwable);
+        if (cause != null) {
+            throwable = cause;
+            while ((throwable = getCause(throwable)) != null) {
+                cause = throwable;
+            }
+        }
+        return cause;
+    }
+
+    /**
+     * <p>Finds a <code>Throwable</code> for known types.</p>
+     * 
+     * <p>Uses <code>instanceof</code> checks to examine the exception,
+     * looking for well known types which could contain chained or
+     * wrapped exceptions.</p>
+     *
+     * @param throwable  the exception to examine
+     * @return the wrapped exception, or <code>null</code> if not found
+     */
+    private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
+        if (throwable instanceof Nestable) {
+            return ((Nestable) throwable).getCause();
+        } else if (throwable instanceof SQLException) {
+            return ((SQLException) throwable).getNextException();
+        } else if (throwable instanceof InvocationTargetException) {
+            return ((InvocationTargetException) throwable).getTargetException();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * <p>Finds a <code>Throwable</code> by method name.</p>
+     * 
+     * @param throwable  the exception to examine
+     * @param methodName  the name of the method to find and invoke
+     * @return the wrapped exception, or <code>null</code> if not found
+     */
+    private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
+        Method method = null;
+        try {
+            method = throwable.getClass().getMethod(methodName, null);
+        } catch (NoSuchMethodException ignored) {
+        } catch (SecurityException ignored) {
+        }
+
+        if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
+            try {
+                return (Throwable) method.invoke(throwable, ArrayUtils.EMPTY_OBJECT_ARRAY);
+            } catch (IllegalAccessException ignored) {
+            } catch (IllegalArgumentException ignored) {
+            } catch (InvocationTargetException ignored) {
+            }
+        }
+        return null;
+    }
+
+    /**
+     * <p>Finds a <code>Throwable</code> by field name.</p>
+     * 
+     * @param throwable  the exception to examine
+     * @param fieldName  the name of the attribute to examine
+     * @return the wrapped exception, or <code>null</code> if not found
+     */
+    private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) {
+        Field field = null;
+        try {
+            field = throwable.getClass().getField(fieldName);
+        } catch (NoSuchFieldException ignored) {
+        } catch (SecurityException ignored) {
+        }
+
+        if (field != null && Throwable.class.isAssignableFrom(field.getType())) {
+            try {
+                return (Throwable) field.get(throwable);
+            } catch (IllegalAccessException ignored) {
+            } catch (IllegalArgumentException ignored) {
+            }
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Checks if the Throwable class has a <code>getCause</code> method.</p>
+     * 
+     * <p>This is true for JDK 1.4 and above.</p>
+     * 
+     * @return true if Throwable is nestable
+     * @since 2.0
+     */
+    public static boolean isThrowableNested() {
+        return (THROWABLE_CAUSE_METHOD != null);
+    }
+    
+    /**
+     * <p>Checks whether this <code>Throwable</code> class can store a cause.</p>
+     * 
+     * <p>This method does <b>not</b> check whether it actually does store a cause.<p>
+     *
+     * @param throwable  the <code>Throwable</code> to examine, may be null
+     * @return boolean <code>true</code> if nested otherwise <code>false</code>
+     * @since 2.0
+     */
+    public static boolean isNestedThrowable(Throwable throwable) {
+        if (throwable == null) {
+            return false;
+        }
+
+        if (throwable instanceof Nestable) {
+            return true;
+        } else if (throwable instanceof SQLException) {
+            return true;
+        } else if (throwable instanceof InvocationTargetException) {
+            return true;
+        } else if (isThrowableNested()) {
+            return true;
+        }
+
+        Class cls = throwable.getClass();
+        for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) {
+            try {
+                Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], null);
+                if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
+                    return true;
+                }
+            } catch (NoSuchMethodException ignored) {
+            } catch (SecurityException ignored) {
+            }
+        }
+
+        try {
+            Field field = cls.getField("detail");
+            if (field != null) {
+                return true;
+            }
+        } catch (NoSuchFieldException ignored) {
+        } catch (SecurityException ignored) {
+        }
+
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Counts the number of <code>Throwable</code> objects in the
+     * exception chain.</p>
+     * 
+     * <p>A throwable without cause will return <code>1</code>.
+     * A throwable with one cause will return <code>2</code> and so on.
+     * A <code>null</code> throwable will return <code>0</code>.</p>
+     * 
+     * @param throwable  the throwable to inspect, may be null
+     * @return the count of throwables, zero if null input
+     */
+    public static int getThrowableCount(Throwable throwable) {
+        int count = 0;
+        while (throwable != null) {
+            count++;
+            throwable = ExceptionUtils.getCause(throwable);
+        }
+        return count;
+    }
+
+    /**
+     * <p>Returns the list of <code>Throwable</code> objects in the
+     * exception chain.</p>
+     * 
+     * <p>A throwable without cause will return an array containing
+     * one element - the input throwable.
+     * A throwable with one cause will return an array containing
+     * two elements. - the input throwable and the cause throwable.
+     * A <code>null</code> throwable will return an array size zero.</p>
+     *
+     * @param throwable  the throwable to inspect, may be null
+     * @return the array of throwables, never null
+     */
+    public static Throwable[] getThrowables(Throwable throwable) {
+        List list = new ArrayList();
+        while (throwable != null) {
+            list.add(throwable);
+            throwable = ExceptionUtils.getCause(throwable);
+        }
+        return (Throwable[]) list.toArray(new Throwable[list.size()]);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Returns the (zero based) index of the first <code>Throwable</code>
+     * that matches the specified type in the exception chain.</p>
+     * 
+     * <p>A <code>null</code> throwable returns <code>-1</code>.
+     * A <code>null</code> type returns <code>-1</code>.
+     * No match in the chain returns <code>-1</code>.</p>
+     *
+     * @param throwable  the throwable to inspect, may be null
+     * @param type  the type to search for
+     * @return the index into the throwable chain, -1 if no match or null input
+     */
+    public static int indexOfThrowable(Throwable throwable, Class type) {
+        return indexOfThrowable(throwable, type, 0);
+    }
+
+    /**
+     * <p>Returns the (zero based) index of the first <code>Throwable</code>
+     * that matches the specified type in the exception chain from
+     * a specified index.</p>
+     * 
+     * <p>A <code>null</code> throwable returns <code>-1</code>.
+     * A <code>null</code> type returns <code>-1</code>.
+     * No match in the chain returns <code>-1</code>.
+     * A negative start index is treated as zero.
+     * A start index greater than the number of throwables returns <code>-1</code>.</p>
+     *
+     * @param throwable  the throwable to inspect, may be null
+     * @param type  the type to search for
+     * @param fromIndex  the (zero based) index of the starting position,
+     *  negative treated as zero, larger than chain size returns -1
+     * @return the index into the throwable chain, -1 if no match or null input
+     */
+    public static int indexOfThrowable(Throwable throwable, Class type, int fromIndex) {
+        if (throwable == null) {
+            return -1;
+        }
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        }
+        Throwable[] throwables = ExceptionUtils.getThrowables(throwable);
+        if (fromIndex >= throwables.length) {
+            return -1;
+        }
+        for (int i = fromIndex; i < throwables.length; i++) {
+            if (throwables[i].getClass().equals(type)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Prints a compact stack trace for the root cause of a throwable
+     * to <code>System.err</code>.</p>
+     * 
+     * <p>The compact stack trace starts with the root cause and prints
+     * stack frames up to the place where it was caught and wrapped.
+     * Then it prints the wrapped exception and continues with stack frames
+     * until the wrapper exception is caught and wrapped again, etc.</p>
+     *
+     * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+     * that don't have nested causes.</p>
+     * 
+     * @param throwable  the throwable to output
+     * @since 2.0
+     */
+    public static void printRootCauseStackTrace(Throwable throwable) {
+        printRootCauseStackTrace(throwable, System.err);
+    }
+
+    /**
+     * <p>Prints a compact stack trace for the root cause of a throwable.</p>
+     *
+     * <p>The compact stack trace starts with the root cause and prints
+     * stack frames up to the place where it was caught and wrapped.
+     * Then it prints the wrapped exception and continues with stack frames
+     * until the wrapper exception is caught and wrapped again, etc.</p>
+     *
+     * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+     * that don't have nested causes.</p>
+     * 
+     * @param throwable  the throwable to output, may be null
+     * @param stream  the stream to output to, may not be null
+     * @throws IllegalArgumentException if the stream is <code>null</code>
+     * @since 2.0
+     */
+    public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) {
+        if (throwable == null) {
+            return;
+        }
+        if (stream == null) {
+            throw new IllegalArgumentException("The PrintStream must not be null");
+        }
+        String trace[] = getRootCauseStackTrace(throwable);
+        for (int i = 0; i < trace.length; i++) {
+            stream.println(trace[i]);
+        }
+        stream.flush();
+    }
+
+    /**
+     * <p>Prints a compact stack trace for the root cause of a throwable.</p>
+     *
+     * <p>The compact stack trace starts with the root cause and prints
+     * stack frames up to the place where it was caught and wrapped.
+     * Then it prints the wrapped exception and continues with stack frames
+     * until the wrapper exception is caught and wrapped again, etc.</p>
+     *
+     * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+     * that don't have nested causes.</p>
+     * 
+     * @param throwable  the throwable to output, may be null
+     * @param writer  the writer to output to, may not be null
+     * @throws IllegalArgumentException if the writer is <code>null</code>
+     * @since 2.0
+     */
+    public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) {
+        if (throwable == null) {
+            return;
+        }
+        if (writer == null) {
+            throw new IllegalArgumentException("The PrintWriter must not be null");
+        }
+        String trace[] = getRootCauseStackTrace(throwable);
+        for (int i = 0; i < trace.length; i++) {
+            writer.println(trace[i]);
+        }
+        writer.flush();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Creates a compact stack trace for the root cause of the supplied
+     * <code>Throwable</code>.</p>
+     * 
+     * @param throwable  the throwable to examine, may be null
+     * @return an array of stack trace frames, never null
+     * @since 2.0
+     */
+    public static String[] getRootCauseStackTrace(Throwable throwable) {
+        if (throwable == null) {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+        Throwable throwables[] = getThrowables(throwable);
+        int count = throwables.length;
+        ArrayList frames = new ArrayList();
+        List nextTrace = getStackFrameList(throwables[count - 1]);
+        for (int i = count; --i >= 0;) {
+            List trace = nextTrace;
+            if (i != 0) {
+                nextTrace = getStackFrameList(throwables[i - 1]);
+                removeCommonFrames(trace, nextTrace);
+            }
+            if (i == count - 1) {
+                frames.add(throwables[i].toString());
+            } else {
+                frames.add(WRAPPED_MARKER + throwables[i].toString());
+            }
+            for (int j = 0; j < trace.size(); j++) {
+                frames.add(trace.get(j));
+            }
+        }
+        return (String[]) frames.toArray(new String[0]);
+    }
+
+    /**
+     * <p>Removes common frames from the cause trace given the two stack traces.</p>
+     * 
+     * @param causeFrames  stack trace of a cause throwable
+     * @param wrapperFrames  stack trace of a wrapper throwable
+     * @throws IllegalArgumentException if either argument is null
+     * @since 2.0
+     */
+    public static void removeCommonFrames(List causeFrames, List wrapperFrames) {
+        if (causeFrames == null || wrapperFrames == null) {
+            throw new IllegalArgumentException("The List must not be null");
+        }
+        int causeFrameIndex = causeFrames.size() - 1;
+        int wrapperFrameIndex = wrapperFrames.size() - 1;
+        while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
+            // Remove the frame from the cause trace if it is the same
+            // as in the wrapper trace
+            String causeFrame = (String) causeFrames.get(causeFrameIndex);
+            String wrapperFrame = (String) wrapperFrames.get(wrapperFrameIndex);
+            if (causeFrame.equals(wrapperFrame)) {
+                causeFrames.remove(causeFrameIndex);
+            }
+            causeFrameIndex--;
+            wrapperFrameIndex--;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Gets the stack trace from a Throwable as a String.</p>
+     *
+     * @param throwable  the <code>Throwable</code> to be examined
+     * @return the stack trace as generated by the exception's
+     *  <code>printStackTrace(PrintWriter)</code> method
+     */
+    public static String getStackTrace(Throwable throwable) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
+        throwable.printStackTrace(pw);
+        return sw.getBuffer().toString();
+    }
+
+    /**
+     * <p>A way to get the entire nested stack-trace of an throwable.</p>
+     *
+     * @param throwable  the <code>Throwable</code> to be examined
+     * @return the nested stack trace, with the root cause first
+     * @since 2.0
+     */
+    public static String getFullStackTrace(Throwable throwable) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
+        Throwable[] ts = getThrowables(throwable);
+        for (int i = 0; i < ts.length; i++) {
+            ts[i].printStackTrace(pw);
+            if (isNestedThrowable(ts[i])) {
+                break;
+            }
+        }
+        return sw.getBuffer().toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Captures the stack trace associated with the specified
+     * <code>Throwable</code> object, decomposing it into a list of
+     * stack frames.</p>
+     *
+     * @param throwable  the <code>Throwable</code> to examine, may be null
+     * @return an array of strings describing each stack frame, never null
+     */
+    public static String[] getStackFrames(Throwable throwable) {
+        if (throwable == null) {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+        return getStackFrames(getStackTrace(throwable));
+    }
+
+    /**
+     * <p>Functionality shared between the
+     * <code>getStackFrames(Throwable)</code> methods of this and the
+     */
+    static String[] getStackFrames(String stackTrace) {
+        String linebreak = SystemUtils.LINE_SEPARATOR;
+        StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
+        List list = new LinkedList();
+        while (frames.hasMoreTokens()) {
+            list.add(frames.nextToken());
+        }
+        return (String[]) list.toArray(new String[list.size()]);
+    }
+
+    /**
+     * <p>Produces a <code>List</code> of stack frames - the message
+     * is not included.</p>
+     *
+     * <p>This works in most cases - it will only fail if the exception
+     * message contains a line that starts with:
+     * <code>&quot;&nbsp;&nbsp;&nbsp;at&quot;.</code></p>
+     * 
+     * @param t is any throwable
+     * @return List of stack frames
+     */
+    static List getStackFrameList(Throwable t) {
+        String stackTrace = getStackTrace(t);
+        String linebreak = SystemUtils.LINE_SEPARATOR;
+        StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
+        List list = new LinkedList();
+        boolean traceStarted = false;
+        while (frames.hasMoreTokens()) {
+            String token = frames.nextToken();
+            // Determine if the line starts with <whitespace>at
+            int at = token.indexOf("at");
+            if (at != -1 && token.substring(0, at).trim().length() == 0) {
+                traceStarted = true;
+                list.add(token);
+            } else if (traceStarted) {
+                break;
+            }
+        }
+        return list;
+    }
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/HashCodeBuilder.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/HashCodeBuilder.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * <p>Assists in implementing {@link Object#hashCode()} methods.</p>
+ *
+ * <p> This class enables a good <code>hashCode</code> method to be built for any class. It
+ * follows the rules laid out in the book
+ * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
+ * by Joshua Bloch. Writing a good <code>hashCode</code> method is actually quite
+ * difficult. This class aims to simplify the process.</p>
+ *
+ * <p>All relevant fields from the object should be included in the
+ * <code>hashCode</code> method. Derived fields may be excluded. In general, any
+ * field used in the <code>equals</code> method must be used in the <code>hashCode</code>
+ * method.</p>
+ *
+ * <p>To use this class write code as follows:</p>
+ * <pre>
+ * public class Person {
+ *   String name;
+ *   int age;
+ *   boolean isSmoker;
+ *   ...
+ *
+ *   public int hashCode() {
+ *     // you pick a hard-coded, randomly chosen, non-zero, odd number
+ *     // ideally different for each class
+ *     return new HashCodeBuilder(17, 37).
+ *       append(name).
+ *       append(age).
+ *       append(smoker).
+ *       toHashCode();
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>If required, the superclass <code>hashCode()</code> can be added
+ * using {@link #appendSuper}.</p>
+ *
+ * <p>Alternatively, there is a method that uses reflection to determine
+ * the fields to test. Because these fields are usually private, the method,
+ * <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code> to
+ * change the visibility of the fields. This will fail under a security manager,
+ * unless the appropriate permissions are set up correctly. It is also slower
+ * than testing explicitly.</p>
+ *
+ * <p>A typical invocation for this method would look like:</p>
+ * <pre>
+ * public int hashCode() {
+ *   return HashCodeBuilder.reflectionHashCode(this);
+ * }
+ * </pre>
+ *
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Pete Gieser
+ * @since 1.0
+ * @version $Id: HashCodeBuilder.java,v 1.22 2004/08/15 02:17:13 bayard Exp $
+ */
+public class HashCodeBuilder {
+
+    /**
+     * Constant to use in building the hashCode.
+     */
+    private final int iConstant;
+    /**
+     * Running total of the hashCode.
+     */
+    private int iTotal = 0;
+
+    /**
+     * <p>Constructor.</p>
+     *
+     * <p>This constructor uses two hard coded choices for the constants
+     * needed to build a <code>hashCode</code>.</p>
+     */
+    public HashCodeBuilder() {
+        super();
+        iConstant = 37;
+        iTotal = 17;
+    }
+
+    /**
+     * <p>Constructor.</p>
+     *
+     * <p>Two randomly chosen, non-zero, odd numbers must be passed in.
+     * Ideally these should be different for each class, however this is
+     * not vital.</p>
+     *
+     * <p>Prime numbers are preferred, especially for the multiplier.</p>
+     *
+     * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
+     * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
+     * @throws IllegalArgumentException if the number is zero or even
+     */
+    public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
+        super();
+        if (initialNonZeroOddNumber == 0) {
+            throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
+        }
+        if (initialNonZeroOddNumber % 2 == 0) {
+            throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
+        }
+        if (multiplierNonZeroOddNumber == 0) {
+            throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
+        }
+        if (multiplierNonZeroOddNumber % 2 == 0) {
+            throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
+        }
+        iConstant = multiplierNonZeroOddNumber;
+        iTotal = initialNonZeroOddNumber;
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>This method uses reflection to build a valid hash code.</p>
+     *
+     * <p>This constructor uses two hard coded choices for the constants
+     * needed to build a hash code.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is
+     * also not as efficient as testing explicitly.</p>
+     *
+     * <p>Transient members will be not be used, as they are likely derived
+     * fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * @param object  the Object to create a <code>hashCode</code> for
+     * @return int hash code
+     * @throws IllegalArgumentException if the object is <code>null</code>
+     */
+    public static int reflectionHashCode(Object object) {
+        return reflectionHashCode(17, 37, object, false, null);
+    }
+
+    /**
+     * <p>This method uses reflection to build a valid hash code.</p>
+     *
+     * <p>This constructor uses two hard coded choices for the constants needed
+     * to build a hash code.</p>
+     *
+     * <p> It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is
+     * also not as efficient as testing explicitly.</p>
+     *
+     * <P>If the TestTransients parameter is set to <code>true</code>, transient
+     * members will be tested, otherwise they are ignored, as they are likely
+     * derived fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * @param object  the Object to create a <code>hashCode</code> for
+     * @param testTransients  whether to include transient fields
+     * @return int hash code
+     * @throws IllegalArgumentException if the object is <code>null</code>
+     */
+    public static int reflectionHashCode(Object object, boolean testTransients) {
+        return reflectionHashCode(17, 37, object, testTransients, null);
+    }
+
+    /**
+     * <p>This method uses reflection to build a valid hash code.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is
+     * also not as efficient as testing explicitly.</p>
+     *
+     * <p>Transient members will be not be used, as they are likely derived
+     * fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
+     * these should be different for each class, however this is not vital.
+     * Prime numbers are preferred, especially for the multiplier.</p>
+     *
+     * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
+     * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
+     * @param object  the Object to create a <code>hashCode</code> for
+     * @return int hash code
+     * @throws IllegalArgumentException if the Object is <code>null</code>
+     * @throws IllegalArgumentException if the number is zero or even
+     */
+    public static int reflectionHashCode(
+            int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
+        return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
+    }
+
+    /**
+     * <p>This method uses reflection to build a valid hash code.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is also
+     * not as efficient as testing explicitly.</p>
+     *
+     * <p>If the TestTransients parameter is set to <code>true</code>, transient
+     * members will be tested, otherwise they are ignored, as they are likely
+     * derived fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be tested. Superclass fields will be included.</p>
+     *
+     * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
+     * these should be different for each class, however this is not vital.
+     * Prime numbers are preferred, especially for the multiplier.</p>
+     *
+     * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
+     * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
+     * @param object  the Object to create a <code>hashCode</code> for
+     * @param testTransients  whether to include transient fields
+     * @return int hash code
+     * @throws IllegalArgumentException if the Object is <code>null</code>
+     * @throws IllegalArgumentException if the number is zero or even
+     */
+    public static int reflectionHashCode(
+            int initialNonZeroOddNumber, int multiplierNonZeroOddNumber,
+            Object object, boolean testTransients) {
+        return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
+    }
+            
+    /**
+     * <p>This method uses reflection to build a valid hash code.</p>
+     *
+     * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
+     * fields. This means that it will throw a security exception if run under
+     * a security manager, if the permissions are not set up correctly. It is also
+     * not as efficient as testing explicitly.</p>
+     *
+     * <p>If the TestTransients parameter is set to <code>true</code>, transient
+     * members will be tested, otherwise they are ignored, as they are likely
+     * derived fields, and not part of the value of the <code>Object</code>.</p>
+     *
+     * <p>Static fields will not be included. Superclass fields will be included
+     * up to and including the specified superclass. A null superclass is treated
+     * as java.lang.Object.</p>
+     *
+     * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
+     * these should be different for each class, however this is not vital.
+     * Prime numbers are preferred, especially for the multiplier.</p>
+     *
+     * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
+     * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
+     * @param object  the Object to create a <code>hashCode</code> for
+     * @param testTransients  whether to include transient fields
+     * @param reflectUpToClass  the superclass to reflect up to (inclusive),
+     *  may be <code>null</code>
+     * @return int hash code
+     * @throws IllegalArgumentException if the Object is <code>null</code>
+     * @throws IllegalArgumentException if the number is zero or even
+     * @since 2.0
+     */
+    public static int reflectionHashCode(
+        int initialNonZeroOddNumber,
+        int multiplierNonZeroOddNumber,
+        Object object,
+        boolean testTransients,
+        Class reflectUpToClass) {
+
+        if (object == null) {
+            throw new IllegalArgumentException("The object to build a hash code for must not be null");
+        }
+        HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
+        Class clazz = object.getClass();
+        reflectionAppend(object, clazz, builder, testTransients);
+        while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
+            clazz = clazz.getSuperclass();
+            reflectionAppend(object, clazz, builder, testTransients);
+        }
+        return builder.toHashCode();
+    }
+
+    /**
+     * <p>Appends the fields and values defined by the given object of the
+     * given <code>Class</code>.</p>
+     * 
+     * @param object  the object to append details of
+     * @param clazz  the class to append details of
+     * @param builder  the builder to append to
+     * @param useTransients  whether to use transient fields
+     */
+    private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients) {
+        Field[] fields = clazz.getDeclaredFields();
+        AccessibleObject.setAccessible(fields, true);
+        for (int i = 0; i < fields.length; i++) {
+            Field f = fields[i];
+            if ((f.getName().indexOf('$') == -1)
+                && (useTransients || !Modifier.isTransient(f.getModifiers()))
+                && (!Modifier.isStatic(f.getModifiers()))) {
+                try {
+                    builder.append(f.get(object));
+                } catch (IllegalAccessException e) {
+                    //this can't happen. Would get a Security exception instead
+                    //throw a runtime exception in case the impossible happens.
+                    throw new InternalError("Unexpected IllegalAccessException");
+                }
+            }
+        }
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>Adds the result of super.hashCode() to this builder.</p>
+     *
+     * @param superHashCode  the result of calling <code>super.hashCode()</code>
+     * @return this HashCodeBuilder, used to chain calls.
+     * @since 2.0
+     */
+    public HashCodeBuilder appendSuper(int superHashCode) {
+        iTotal = iTotal * iConstant + superHashCode;
+        return this;
+    }
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * <p>Append a <code>hashCode</code> for an <code>Object</code>.</p>
+     *
+     * @param object  the Object to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(Object object) {
+        if (object == null) {
+            iTotal = iTotal * iConstant;
+
+        } else {
+            if (object.getClass().isArray() == false) {
+                //the simple case, not an array, just the element
+                iTotal = iTotal * iConstant + object.hashCode();
+
+            } else {
+                //'Switch' on type of array, to dispatch to the correct handler
+                // This handles multi dimensional arrays
+                if (object instanceof long[]) {
+                    append((long[]) object);
+                } else if (object instanceof int[]) {
+                    append((int[]) object);
+                } else if (object instanceof short[]) {
+                    append((short[]) object);
+                } else if (object instanceof char[]) {
+                    append((char[]) object);
+                } else if (object instanceof byte[]) {
+                    append((byte[]) object);
+                } else if (object instanceof double[]) {
+                    append((double[]) object);
+                } else if (object instanceof float[]) {
+                    append((float[]) object);
+                } else if (object instanceof boolean[]) {
+                    append((boolean[]) object);
+                } else {
+                    // Not an array of primitives
+                    append((Object[]) object);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>long</code>.</p>
+     *
+     * @param value  the long to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(long value) {
+        iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for an <code>int</code>.</p>
+     *
+     * @param value  the int to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(int value) {
+        iTotal = iTotal * iConstant + value;
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>short</code>.</p>
+     *
+     * @param value  the short to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(short value) {
+        iTotal = iTotal * iConstant + value;
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>char</code>.</p>
+     *
+     * @param value  the char to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(char value) {
+        iTotal = iTotal * iConstant + value;
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>byte</code>.</p>
+     *
+     * @param value  the byte to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(byte value) {
+        iTotal = iTotal * iConstant + value;
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>double</code>.</p>
+     *
+     * @param value  the double to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(double value) {
+        return append(Double.doubleToLongBits(value));
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>float</code>.</p>
+     *
+     * @param value  the float to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(float value) {
+        iTotal = iTotal * iConstant + Float.floatToIntBits(value);
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>boolean</code>.</p>
+     * <p>This adds <code>iConstant * 1</code> to the <code>hashCode</code>
+     * and not a <code>1231</code> or <code>1237</code> as done in java.lang.Boolean. 
+     * This is in accordance with the Effective Java design. </p>
+     *
+     * @param value  the boolean to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(boolean value) {
+        iTotal = iTotal * iConstant + (value ? 0 : 1);
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for an <code>Object</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(Object[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>long</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(long[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for an <code>int</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(int[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>short</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(short[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>char</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(char[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>byte</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(byte[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>double</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(double[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>float</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(float[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append a <code>hashCode</code> for a <code>boolean</code> array.</p>
+     *
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public HashCodeBuilder append(boolean[] array) {
+        if (array == null) {
+            iTotal = iTotal * iConstant;
+        } else {
+            for (int i = 0; i < array.length; i++) {
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * <p>Return the computed <code>hashCode</code>.</p>
+     *
+     * @return <code>hashCode</code> based on the fields appended
+     */
+    public int toHashCode() {
+        return iTotal;
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/MultiMap.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/MultiMap.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,159 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.util.Collection;
+import java.util.Map;
+
+/** 
+ * Defines a map that holds a collection of values against each key.
+ * <p>
+ * A <code>MultiMap</code> is a Map with slightly different semantics.
+ * Putting a value into the map will add the value to a Collection at that key.
+ * Getting a value will return a Collection, holding all the values put to that key.
+ * <p>
+ * For example:
+ * <pre>
+ * MultiMap mhm = new MultiHashMap();
+ * mhm.put(key, "A");
+ * mhm.put(key, "B");
+ * mhm.put(key, "C");
+ * Collection coll = (Collection) mhm.get(key);</pre>
+ * <p>
+ * <code>coll</code> will be a collection containing "A", "B", "C".
+ * <p>
+ * NOTE: Additional methods were added to this interface in Commons Collections 3.1.
+ * These were added solely for documentation purposes and do not change the interface
+ * as they were defined in the superinterface <code>Map</code> anyway.
+ *
+ * @since Commons Collections 2.0
+ * @version $Revision: 1.12 $ $Date: 2004/03/14 15:33:57 $
+ * 
+ * @author Christopher Berry
+ * @author James Strachan
+ * @author Stephen Colebourne
+ */
+public interface MultiMap extends Map {
+
+    /**
+     * Removes a specific value from map.
+     * <p>
+     * The item is removed from the collection mapped to the specified key.
+     * Other values attached to that key are unaffected.
+     * <p>
+     * If the last value for a key is removed, implementations typically
+     * return <code>null</code> from a subsequant <code>get(Object)</code>, however
+     * they may choose to return an empty collection.
+     * 
+     * @param key  the key to remove from
+     * @param item  the item to remove
+     * @return the value removed (which was passed in), null if nothing removed
+     * @throws UnsupportedOperationException if the map is unmodifiable
+     * @throws ClassCastException if the key or value is of an invalid type
+     * @throws NullPointerException if the key or value is null and null is invalid
+     */
+    public Object remove(Object key, Object item);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of keys in this map.
+     * <p>
+     * Implementations typically return only the count of keys in the map
+     * This cannot be mandated due to backwards compatability of this interface.
+     *
+     * @return the number of key-collection mappings in this map
+     */
+    int size();
+
+    /**
+     * Gets the collection of values associated with the specified key.
+     * <p>
+     * The returned value will implement <code>Collection</code>. Implementations
+     * are free to declare that they return <code>Collection</code> subclasses
+     * such as <code>List</code> or <code>Set</code>.
+     * <p>
+     * Implementations typically return <code>null</code> if no values have
+     * been mapped to the key, however the implementation may choose to
+     * return an empty collection.
+     * <p>
+     * Implementations may choose to return a clone of the internal collection.
+     *
+     * @param key  the key to retrieve
+     * @return the <code>Collection</code> of values, implementations should
+     *  return <code>null</code> for no mapping, but may return an empty collection
+     * @throws ClassCastException if the key is of an invalid type
+     * @throws NullPointerException if the key is null and null keys are invalid
+     */
+    Object get(Object key);
+
+    /**
+     * Checks whether the map contains the value specified.
+     * <p>
+     * Implementations typically check all collections against all keys for the value.
+     * This cannot be mandated due to backwards compatability of this interface.
+     *
+     * @param value  the value to search for
+     * @return true if the map contains the value
+     * @throws ClassCastException if the value is of an invalid type
+     * @throws NullPointerException if the value is null and null value are invalid
+     */
+    boolean containsValue(Object value);
+
+    /**
+     * Adds the value to the collection associated with the specified key.
+     * <p>
+     * Unlike a normal <code>Map</code> the previous value is not replaced.
+     * Instead the new value is added to the collection stored against the key.
+     * The collection may be a <code>List</code>, <code>Set</code> or other
+     * collection dependent on implementation.
+     *
+     * @param key  the key to store against
+     * @param value  the value to add to the collection at the key
+     * @return typically the value added if the map changed and null if the map did not change
+     * @throws UnsupportedOperationException if the map is unmodifiable
+     * @throws ClassCastException if the key or value is of an invalid type
+     * @throws NullPointerException if the key or value is null and null is invalid
+     * @throws IllegalArgumentException if the key or value is invalid
+     */
+    Object put(Object key, Object value);
+
+    /**
+     * Removes all values associated with the specified key.
+     * <p>
+     * Implementations typically return <code>null</code> from a subsequant
+     * <code>get(Object)</code>, however they may choose to return an empty collection.
+     *
+     * @param key  the key to remove values from
+     * @return the <code>Collection</code> of values removed, implementations should
+     *  return <code>null</code> for no mapping found, but may return an empty collection
+     * @throws UnsupportedOperationException if the map is unmodifiable
+     * @throws ClassCastException if the key is of an invalid type
+     * @throws NullPointerException if the key is null and null keys are invalid
+     */
+    Object remove(Object key);
+
+    /**
+     * Gets a collection containing all the values in the map.
+     * <p>
+     * Inplementations typically return a collection containing the combination
+     * of values from all keys.
+     * This cannot be mandated due to backwards compatability of this interface.
+     *
+     * @return a collection view of the values contained in this map
+     */
+    Collection values();
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Nestable.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/Nestable.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+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>
+ * @author <a href="mailto:steven@caswell.name">Steven Caswell</a>
+ * @author Pete Gieser
+ * @since 1.0
+ * @version $Id: Nestable.java,v 1.11 2004/02/18 22:54:04 ggregory Exp $
+ */
+public interface Nestable {
+    
+    /**
+     * Returns the reference to the exception or error that caused the
+     * exception implementing the <code>Nestable</code> to be thrown.
+     *
+     * @return throwable that caused the original exception
+     */
+    public Throwable getCause();
+
+    /**
+     * Returns the error message of this and any nested
+     * <code>Throwable</code>.
+     *
+     * @return the error message
+     */
+    public String getMessage();
+
+    /**
+     * Returns the error message of the <code>Throwable</code> in the chain
+     * of <code>Throwable</code>s at the specified index, numbered from 0.
+     *
+     * @param index the index of the <code>Throwable</code> in the chain of
+     * <code>Throwable</code>s
+     * @return the error message, or null if the <code>Throwable</code> at the
+     * specified index in the chain does not contain a message
+     * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+     * negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     */
+    public String getMessage(int index);
+
+    /**
+     * Returns the error message of this and any nested <code>Throwable</code>s
+     * in an array of Strings, one element for each message. Any
+     * <code>Throwable</code> not containing a message is represented in the
+     * array by a null. This has the effect of cause the length of the returned
+     * array to be equal to the result of the {@link #getThrowableCount()}
+     * operation.
+     *
+     * @return the error messages
+     */
+    public String[] getMessages();
+
+    /**
+     * Returns the <code>Throwable</code> in the chain of
+     * <code>Throwable</code>s at the specified index, numbered from 0.
+     *
+     * @param index the index, numbered from 0, of the <code>Throwable</code> in
+     * the chain of <code>Throwable</code>s
+     * @return the <code>Throwable</code>
+     * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+     * negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     */
+    public Throwable getThrowable(int index);
+
+    /**
+     * Returns the number of nested <code>Throwable</code>s represented by
+     * this <code>Nestable</code>, including this <code>Nestable</code>.
+     *
+     * @return the throwable count
+     */
+    public int getThrowableCount();
+
+    /**
+     * Returns this <code>Nestable</code> and any nested <code>Throwable</code>s
+     * in an array of <code>Throwable</code>s, one element for each
+     * <code>Throwable</code>.
+     *
+     * @return the <code>Throwable</code>s
+     */
+    public Throwable[] getThrowables();
+
+    /**
+     * Returns the index, numbered from 0, of the first occurrence of the
+     * specified type in the chain of <code>Throwable</code>s, or -1 if the
+     * specified type is not found in the chain.
+     *
+     * @param type <code>Class</code> to be found
+     * @return index of the first occurrence of the type in the chain, or -1 if
+     * the type is not found
+     */
+    public int indexOfThrowable(Class type);
+
+    /**
+     * Returns the index, numbered from 0, of the first <code>Throwable</code>
+     * that matches the specified type in the chain of <code>Throwable</code>s
+     * with an index greater than or equal to the specified index, or -1 if
+     * the type is not found.
+     *
+     * @param type <code>Class</code> to be found
+     * @param fromIndex the index, numbered from 0, of the starting position in
+     * the chain to be searched
+     * @return index of the first occurrence of the type in the chain, or -1 if
+     * the type is not found
+     * @throws IndexOutOfBoundsException if the <code>fromIndex</code> argument
+     * is negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     */
+    public int indexOfThrowable(Class type, int fromIndex);
+
+    /**
+     * Prints the stack trace of this exception to the specified print
+     * writer.  Includes information 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 of this exception to the specified print
+     * stream.  Includes information from the exception, if any,
+     * which caused this exception.
+     *
+     * @param out <code>PrintStream</code> to use for output.
+     */
+    public void printStackTrace(PrintStream 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);
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableDelegate.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableDelegate.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <p>A shared implementation of the nestable exception functionality.</p>
+ * <p>
+ * The code is shared between 
+ * </p>
+ * 
+ * @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>
+ * @author <a href="mailto:steven@caswell.name">Steven Caswell</a>
+ * @author Sean C. Sullivan
+ * @author Stephen Colebourne
+ * @since 1.0
+ * @version $Id: NestableDelegate.java,v 1.23 2004/02/18 22:54:04 ggregory Exp $
+ */
+public class NestableDelegate implements Serializable {
+
+    /**
+     * Constructor error message.
+     */
+    private transient 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 we're
+     * wrapping (which must be a {@link
+     * org.apache.commons.lang.exception.Nestable} implementation).
+     */
+    private Throwable nestable = null;
+    
+    /**
+     * Whether to print the stack trace top-down.
+     * This public flag may be set by calling code, typically in initialisation.
+     * @since 2.0
+     */
+    public static boolean topDown = true;
+    
+    /**
+     * Whether to trim the repeated stack trace.
+     * This public flag may be set by calling code, typically in initialisation.
+     * @since 2.0
+     */
+    public static boolean trimStackFrames = true;
+
+    /**
+     * Constructs a new <code>NestableDelegate</code> instance to manage the
+     * specified <code>Nestable</code>.
+     *
+     * @param nestable the Nestable implementation (<i>must</i> extend
+     * {@link java.lang.Throwable})
+     * @since 2.0
+     */
+    public NestableDelegate(Nestable nestable) {
+        if (nestable instanceof Throwable) {
+            this.nestable = (Throwable) nestable;
+        } else {
+            throw new IllegalArgumentException(MUST_BE_THROWABLE);
+        }
+    }
+
+    /**
+     * Returns the error message of the <code>Throwable</code> in the chain
+     * of <code>Throwable</code>s at the specified index, numbered from 0.
+     *
+     * @param index the index of the <code>Throwable</code> in the chain of
+     * <code>Throwable</code>s
+     * @return the error message, or null if the <code>Throwable</code> at the
+     * specified index in the chain does not contain a message
+     * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+     * negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     * @since 2.0
+     */
+    public String getMessage(int index) {
+        Throwable t = this.getThrowable(index);
+        if (Nestable.class.isInstance(t)) {
+            return ((Nestable) t).getMessage(0);
+        } else {
+            return t.getMessage();
+        }
+    }
+
+    /**
+     * Returns the full message contained by the <code>Nestable</code>
+     * and any nested <code>Throwable</code>s.
+     *
+     * @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
+     * <code>Throwable</code>s
+     * @since 2.0
+     */
+    public String getMessage(String baseMsg) {
+        StringBuffer msg = new StringBuffer();
+        if (baseMsg != null) {
+            msg.append(baseMsg);
+        }
+
+        Throwable nestedCause = ExceptionUtils.getCause(this.nestable);
+        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);
+    }
+
+    /**
+     * Returns the error message of this and any nested <code>Throwable</code>s
+     * in an array of Strings, one element for each message. Any
+     * <code>Throwable</code> not containing a message is represented in the
+     * array by a null. This has the effect of cause the length of the returned
+     * array to be equal to the result of the {@link #getThrowableCount()}
+     * operation.
+     *
+     * @return the error messages
+     * @since 2.0
+     */
+    public String[] getMessages() {
+        Throwable[] throwables = this.getThrowables();
+        String[] msgs = new String[throwables.length];
+        for (int i = 0; i < throwables.length; i++) {
+            msgs[i] =
+                (Nestable.class.isInstance(throwables[i])
+                    ? ((Nestable) throwables[i]).getMessage(0)
+                    : throwables[i].getMessage());
+        }
+        return msgs;
+    }
+
+    /**
+     * Returns the <code>Throwable</code> in the chain of
+     * <code>Throwable</code>s at the specified index, numbered from 0.
+     *
+     * @param index the index, numbered from 0, of the <code>Throwable</code> in
+     * the chain of <code>Throwable</code>s
+     * @return the <code>Throwable</code>
+     * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+     * negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     * @since 2.0
+     */
+    public Throwable getThrowable(int index) {
+        if (index == 0) {
+            return this.nestable;
+        }
+        Throwable[] throwables = this.getThrowables();
+        return throwables[index];
+    }
+
+    /**
+     * Returns the number of <code>Throwable</code>s contained in the
+     * <code>Nestable</code> contained by this delegate.
+     *
+     * @return the throwable count
+     * @since 2.0
+     */
+    public int getThrowableCount() {
+        return ExceptionUtils.getThrowableCount(this.nestable);
+    }
+
+    /**
+     * Returns this delegate's <code>Nestable</code> and any nested
+     * <code>Throwable</code>s in an array of <code>Throwable</code>s, one
+     * element for each <code>Throwable</code>.
+     *
+     * @return the <code>Throwable</code>s
+     * @since 2.0
+     */
+    public Throwable[] getThrowables() {
+        return ExceptionUtils.getThrowables(this.nestable);
+    }
+
+    /**
+     * Returns the index, numbered from 0, of the first <code>Throwable</code>
+     * that matches the specified type in the chain of <code>Throwable</code>s
+     * held in this delegate's <code>Nestable</code> with an index greater than
+     * or equal to the specified index, or -1 if the type is not found.
+     *
+     * @param type <code>Class</code> to be found
+     * @param fromIndex the index, numbered from 0, of the starting position in
+     * the chain to be searched
+     * @return index of the first occurrence of the type in the chain, or -1 if
+     * the type is not found
+     * @throws IndexOutOfBoundsException if the <code>fromIndex</code> argument
+     * is negative or not less than the count of <code>Throwable</code>s in the
+     * chain
+     * @since 2.0
+     */
+    public int indexOfThrowable(Class type, int fromIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("The start index was out of bounds: " + fromIndex);
+        }
+        Throwable[] throwables = ExceptionUtils.getThrowables(this.nestable);
+        if (fromIndex >= throwables.length) {
+            throw new IndexOutOfBoundsException("The start index was out of bounds: "
+                + fromIndex + " >= " + throwables.length);
+        }
+        for (int i = fromIndex; i < throwables.length; i++) {
+            if (throwables[i].getClass().equals(type)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Prints the stack trace of this exception the the standar error
+     * stream.
+     */
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Prints the stack trace of this exception to the specified
+     * stream.
+     *
+     * @param out <code>PrintStream</code> to use for output.
+     * @see #printStackTrace(PrintWriter)
+     */
+    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
+     * writer. If the Throwable class has a <code>getCause</code>
+     * method (i.e. running on jre1.4 or higher), this method just 
+     * uses Throwable's printStackTrace() method. Otherwise, generates
+     * the stack-trace, by taking into account the 'topDown' and 
+     * 'trimStackFrames' parameters. The topDown and trimStackFrames 
+     * are set to 'true' by default (produces jre1.4-like stack trace).
+     *
+     * @param out <code>PrintWriter</code> to use for output.
+     */
+    public void printStackTrace(PrintWriter out) {
+        Throwable throwable = this.nestable;
+        // if running on jre1.4 or higher, use default printStackTrace
+        if (ExceptionUtils.isThrowableNested()) {
+            if (throwable instanceof Nestable) {
+                ((Nestable)throwable).printPartialStackTrace(out);
+            } else {
+                throwable.printStackTrace(out);
+            }
+            return;
+        }
+
+        // generating the nested stack trace
+        List stacks = new ArrayList();
+        while (throwable != null) {
+            String[] st = getStackFrames(throwable);
+            stacks.add(st);
+            throwable = ExceptionUtils.getCause(throwable);
+        }
+
+        // If NOT topDown, reverse the stack
+        String separatorLine = "Caused by: ";
+        if (!topDown) {
+            separatorLine = "Rethrown as: ";
+            Collections.reverse(stacks);
+        }
+
+        // Remove the repeated lines in the stack
+        if (trimStackFrames) {
+          trimStackFrames(stacks);
+        }
+
+        synchronized (out) {
+            for (Iterator iter=stacks.iterator(); iter.hasNext();) {
+                String[] st = (String[]) iter.next();
+                for (int i=0, len=st.length; i < len; i++) {
+                    out.println(st[i]);
+                }
+                if (iter.hasNext()) {
+                    out.print(separatorLine);
+                }
+            }
+        }
+    }
+
+    /**
+     * Captures the stack trace associated with the specified
+     * <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.
+     * @since 2.0
+     */
+    protected String[] getStackFrames(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);
+        }
+        return ExceptionUtils.getStackFrames(sw.getBuffer().toString());
+    }
+    
+    /**
+     * Trims the stack frames. The first set is left untouched. The rest
+     * of the frames are truncated from the bottom by comparing with
+     * one just on top.
+     *
+     * @param stacks The list containing String[] elements
+     * @since 2.0
+     */
+    protected void trimStackFrames(List stacks) {
+         for (int size=stacks.size(), i=size-1; i > 0; i--) {
+             String[] curr = (String[]) stacks.get(i);
+             String[] next = (String[]) stacks.get(i-1); 
+             
+             List currList = new ArrayList(Arrays.asList(curr));
+             List nextList = new ArrayList(Arrays.asList(next));
+             ExceptionUtils.removeCommonFrames(currList, nextList);
+
+             int trimmed = curr.length - currList.size();
+             if (trimmed > 0) {
+                 currList.add("\t... "+trimmed+" more");
+                 stacks.set(
+                     i, 
+                     currList.toArray(new String[currList.size()])
+                 );
+             }
+         }
+     }
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableError.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableError.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * The base class of all errors which can contain other exceptions.
+ *
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @since 1.0
+ * @version $Id: NestableError.java,v 1.8 2004/02/18 22:54:04 ggregory Exp $
+ */
+public class NestableError extends Error 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>NestableError</code> without specified
+     * detail message.
+     */
+    public NestableError() {
+        super();
+    }
+
+    /**
+     * Constructs a new <code>NestableError</code> with specified
+     * detail message.
+     *
+     * @param msg The error message.
+     */
+    public NestableError(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new <code>NestableError</code> with specified
+     * nested <code>Throwable</code>.
+     *
+     * @param cause the exception or error that caused this exception to be
+     * thrown
+     */
+    public NestableError(Throwable cause) {
+        super();
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs a new <code>NestableError</code> with specified
+     * detail message and nested <code>Throwable</code>.
+     *
+     * @param msg    the error message
+     * @param cause  the exception or error that caused this exception to be
+     * thrown
+     */
+    public NestableError(String msg, Throwable cause) {
+        super(msg);
+        this.cause = cause;
+    }
+
+    public Throwable getCause() {
+        return cause;
+    }
+
+    /**
+     * Returns the detail message string of this throwable. If it was
+     * created with a null message, returns the following:
+     * (cause==null ? null : cause.toString()).
+     */
+    public String getMessage() {
+        if (super.getMessage() != null) {
+            return super.getMessage();
+        } else if (cause != null) {
+            return cause.toString();
+        } else {
+            return null;
+        }
+    }
+
+    public String getMessage(int index) {
+        if (index == 0) {
+            return super.getMessage();
+        } else {
+            return delegate.getMessage(index);
+        }
+    }
+
+    public String[] getMessages() {
+        return delegate.getMessages();
+    }
+
+    public Throwable getThrowable(int index) {
+        return delegate.getThrowable(index);
+    }
+
+    public int getThrowableCount() {
+        return delegate.getThrowableCount();
+    }
+
+    public Throwable[] getThrowables() {
+        return delegate.getThrowables();
+    }
+
+    public int indexOfThrowable(Class type) {
+        return delegate.indexOfThrowable(type, 0);
+    }
+
+    public int indexOfThrowable(Class type, int fromIndex) {
+        return delegate.indexOfThrowable(type, fromIndex);
+    }
+
+    public void printStackTrace() {
+        delegate.printStackTrace();
+    }
+
+    public void printStackTrace(PrintStream out) {
+        delegate.printStackTrace(out);
+    }
+
+    public void printStackTrace(PrintWriter out) {
+        delegate.printStackTrace(out);
+    }
+
+    public final void printPartialStackTrace(PrintWriter out) {
+        super.printStackTrace(out);
+    }
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableException.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableException.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * 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 descendants of <code>NestedException</code>, when the
+ * exception is finally printed out using any of the <code>
+ * printStackTrace()</code> methods, the stack trace 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.lang.exception.NestableException;
+ *  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 NestableException("foo", e);
+ * 17          }
+ * 18      }
+ * 19
+ * 20      public static void b() throws Exception {
+ * 21          try {
+ * 22              c();
+ * 23          } catch(Exception e) {
+ * 24              throw new NestableException("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 stack trace:
+ * <p><blockquote><pre>
+ * org.apache.commons.lang.exception.NestableException: foo
+ *         at Test.a(Test.java:16)
+ *         at Test.main(Test.java:6)
+ * Caused by: org.apache.commons.lang.exception.NestableException: bar
+ *         at Test.b(Test.java:24)
+ *         at Test.a(Test.java:14)
+ *         ... 1 more
+ * Caused by: java.lang.Exception: baz
+ *         at Test.c(Test.java:29)
+ *         at Test.b(Test.java:22)
+ *         ... 2 more
+ * </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>
+ * @author <a href="mailto:steven@caswell.name">Steven Caswell</a>
+ * @since 1.0
+ * @version $Id: NestableException.java,v 1.12 2004/08/04 18:41:09 ggregory Exp $
+ */
+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 cause 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 cause  the exception or error that caused this exception to be
+     * thrown
+     */
+    public NestableException(String msg, Throwable cause) {
+        super(msg);
+        this.cause = cause;
+    }
+
+    public Throwable getCause() {
+        return cause;
+    }
+
+    /**
+     * Returns the detail message string of this throwable. If it was
+     * created with a null message, returns the following:
+     * (cause==null ? null : cause.toString()).
+     */
+    public String getMessage() {
+        if (super.getMessage() != null) {
+            return super.getMessage();
+        } else if (cause != null) {
+            return cause.toString();
+        } else {
+            return null;
+        }
+    }
+
+    public String getMessage(int index) {
+        if (index == 0) {
+            return super.getMessage();
+        } else {
+            return delegate.getMessage(index);
+        }
+    }
+
+    public String[] getMessages() {
+        return delegate.getMessages();
+    }
+
+    public Throwable getThrowable(int index) {
+        return delegate.getThrowable(index);
+    }
+
+    public int getThrowableCount() {
+        return delegate.getThrowableCount();
+    }
+
+    public Throwable[] getThrowables() {
+        return delegate.getThrowables();
+    }
+
+    public int indexOfThrowable(Class type) {
+        return delegate.indexOfThrowable(type, 0);
+    }
+
+    public int indexOfThrowable(Class type, int fromIndex) {
+        return delegate.indexOfThrowable(type, fromIndex);
+    }
+
+    public void printStackTrace() {
+        delegate.printStackTrace();
+    }
+
+    public void printStackTrace(PrintStream out) {
+        delegate.printStackTrace(out);
+    }
+
+    public void printStackTrace(PrintWriter out) {
+        delegate.printStackTrace(out);
+    }
+
+    public final void printPartialStackTrace(PrintWriter out) {
+        super.printStackTrace(out);
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableRuntimeException.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/NestableRuntimeException.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * The base class of all runtime exceptions which can contain other
+ * exceptions.
+ *
+ * @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>
+ * @author <a href="mailto:steven@caswell.name">Steven Caswell</a>
+ * @since 1.0
+ * @version $Id: NestableRuntimeException.java,v 1.10 2004/02/18 22:54:04 ggregory Exp $
+ */
+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 cause 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 cause  the exception or error that caused this exception to be
+     * thrown
+     */
+    public NestableRuntimeException(String msg, Throwable cause) {
+        super(msg);
+        this.cause = cause;
+    }
+
+    public Throwable getCause() {
+        return cause;
+    }
+
+    /**
+     * Returns the detail message string of this throwable. If it was
+     * created with a null message, returns the following:
+     * (cause==null ? null : cause.toString()).
+     */
+    public String getMessage() {
+        if (super.getMessage() != null) {
+            return super.getMessage();
+        } else if (cause != null) {
+            return cause.toString();
+        } else {
+            return null;
+        }
+    }
+
+    public String getMessage(int index) {
+        if (index == 0) {
+            return super.getMessage();
+        } else {
+            return delegate.getMessage(index);
+        }
+    }
+
+    public String[] getMessages() {
+        return delegate.getMessages();
+    }
+
+    public Throwable getThrowable(int index) {
+        return delegate.getThrowable(index);
+    }
+
+    public int getThrowableCount() {
+        return delegate.getThrowableCount();
+    }
+
+    public Throwable[] getThrowables() {
+        return delegate.getThrowables();
+    }
+
+    public int indexOfThrowable(Class type) {
+        return delegate.indexOfThrowable(type, 0);
+    }
+
+    public int indexOfThrowable(Class type, int fromIndex) {
+        return delegate.indexOfThrowable(type, fromIndex);
+    }
+
+    public void printStackTrace() {
+        delegate.printStackTrace();
+    }
+
+    public void printStackTrace(PrintStream out) {
+        delegate.printStackTrace(out);
+    }
+
+    public void printStackTrace(PrintWriter out) {
+        delegate.printStackTrace(out);
+    }
+
+    public final void printPartialStackTrace(PrintWriter out) {
+        super.printStackTrace(out);
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ObjectUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ObjectUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.Serializable;
+
+/**
+ * <p>Operations on <code>Object</code>.</p>
+ * 
+ * <p>This class tries to handle <code>null</code> input gracefully.
+ * An exception will generally not be thrown for a <code>null</code> input.
+ * Each method documents its behaviour in more detail.</p>
+ *
+ * @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>
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Mario Winterer
+ * @since 1.0
+ * @version $Id: ObjectUtils.java,v 1.24 2004/06/01 21:08:48 scolebourne Exp $
+ */
+public class ObjectUtils {
+    
+    /**
+     * <p>Singleton used as a <code>null</code> placeholder where
+     * <code>null</code> has another meaning.</p>
+     *
+     * <p>For example, in a <code>HashMap</code> the
+     * {@link java.util.HashMap#get(java.lang.Object)} method returns
+     * <code>null</code> if the <code>Map</code> contains
+     * <code>null</code> or if there is no matching key. The
+     * <code>Null</code> placeholder can be used to distinguish between
+     * these two cases.</p>
+     *
+     * <p>Another example is <code>Hashtable</code>, where <code>null</code>
+     * cannot be stored.</p>
+     *
+     * <p>This instance is Serializable.</p>
+     */
+    public static final Null NULL = new Null();
+    
+    /**
+     * <p><code>ObjectUtils</code> instances should NOT be constructed in
+     * standard programming. Instead, the class should be used as
+     * <code>ObjectUtils.defaultIfNull("a","b");</code>.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean instance
+     * to operate.</p>
+     */
+    public ObjectUtils() {
+    }
+
+    // Defaulting
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Returns a default value if the object passed is
+     * <code>null</code>.</p>
+     * 
+     * <pre>
+     * ObjectUtils.defaultIfNull(null, null)      = null
+     * ObjectUtils.defaultIfNull(null, "")        = ""
+     * ObjectUtils.defaultIfNull(null, "zz")      = "zz"
+     * ObjectUtils.defaultIfNull("abc", *)        = "abc"
+     * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
+     * </pre>
+     *
+     * @param object  the <code>Object</code> to test, may be <code>null</code>
+     * @param defaultValue  the default value to return, may be <code>null</code>
+     * @return <code>object</code> if it is not <code>null</code>, defaultValue otherwise
+     */
+    public static Object defaultIfNull(Object object, Object defaultValue) {
+        return (object != null ? object : defaultValue);
+    }
+
+    /**
+     * <p>Compares two objects for equality, where either one or both
+     * objects may be <code>null</code>.</p>
+     *
+     * <pre>
+     * ObjectUtils.equals(null, null)                  = true
+     * ObjectUtils.equals(null, "")                    = false
+     * ObjectUtils.equals("", null)                    = false
+     * ObjectUtils.equals("", "")                      = true
+     * ObjectUtils.equals(Boolean.TRUE, null)          = false
+     * ObjectUtils.equals(Boolean.TRUE, "true")        = false
+     * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
+     * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
+     * </pre>
+     *
+     * @param object1  the first object, may be <code>null</code>
+     * @param object2  the second object, may be <code>null</code>
+     * @return <code>true</code> if the values of both objects are the same
+     */
+    public static boolean equals(Object object1, Object object2) {
+        if (object1 == object2) {
+            return true;
+        }
+        if ((object1 == null) || (object2 == null)) {
+            return false;
+        }
+        return object1.equals(object2);
+    }
+
+    /**
+     * <p>Gets the hash code of an object returning zero when the
+     * object is <code>null</code>.</p>
+     *
+     * <pre>
+     * ObjectUtils.hashCode(null)   = 0
+     * ObjectUtils.hashCode(obj)    = obj.hashCode()
+     * </pre>
+     *
+     * @param obj  the object to obtain the hash code of, may be <code>null</code>
+     * @return the hash code of the object, or zero if null
+     * @since 2.1
+     */
+    public static int hashCode(Object obj) {
+        return ((obj == null) ? 0 : obj.hashCode());
+    }
+
+    // Identity ToString
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Gets the toString that would be produced by <code>Object</code>
+     * if a class did not override toString itself. <code>null</code>
+     * will return <code>null</code>.</p>
+     *
+     * <pre>
+     * ObjectUtils.identityToString(null)         = null
+     * ObjectUtils.identityToString("")           = "java.lang.String@1e23"
+     * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
+     * </pre>
+     *
+     * @param object  the object to create a toString for, may be
+     *  <code>null</code>
+     * @return the default toString text, or <code>null</code> if
+     *  <code>null</code> passed in
+     */
+    public static String identityToString(Object object) {
+        if (object == null) {
+            return null;
+        }
+        return appendIdentityToString(null, object).toString();
+    }
+
+    /**
+     * <p>Appends the toString that would be produced by <code>Object</code>
+     * if a class did not override toString itself. <code>null</code>
+     * will return <code>null</code>.</p>
+     *
+     * <pre>
+     * ObjectUtils.appendIdentityToString(*, null)            = null
+     * ObjectUtils.appendIdentityToString(null, "")           = "java.lang.String@1e23"
+     * ObjectUtils.appendIdentityToString(null, Boolean.TRUE) = "java.lang.Boolean@7fa"
+     * ObjectUtils.appendIdentityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa")
+     * </pre>
+     *
+     * @param buffer  the buffer to append to, may be <code>null</code>
+     * @param object  the object to create a toString for, may be <code>null</code>
+     * @return the default toString text, or <code>null</code> if
+     *  <code>null</code> passed in
+     * @since 2.0
+     */
+    public static StringBuffer appendIdentityToString(StringBuffer buffer, Object object) {
+        if (object == null) {
+            return null;
+        }
+        if (buffer == null) {
+            buffer = new StringBuffer();
+        }
+        return buffer
+            .append(object.getClass().getName())
+            .append('@')
+            .append(Integer.toHexString(System.identityHashCode(object)));
+    }
+
+    // ToString
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Gets the <code>toString</code> of an <code>Object</code> returning
+     * an empty string ("") if <code>null</code> input.</p>
+     * 
+     * <pre>
+     * ObjectUtils.toString(null)         = ""
+     * ObjectUtils.toString("")           = ""
+     * ObjectUtils.toString("bat")        = "bat"
+     * ObjectUtils.toString(Boolean.TRUE) = "true"
+     * </pre>
+     * 
+     * @see String#valueOf(Object)
+     * @param obj  the Object to <code>toString</code>, may be null
+     * @return the passed in Object's toString, or nullStr if <code>null</code> input
+     * @since 2.0
+     */
+    public static String toString(Object obj) {
+        return (obj == null ? "" : obj.toString());
+    }
+
+    /**
+     * <p>Gets the <code>toString</code> of an <code>Object</code> returning
+     * a specified text if <code>null</code> input.</p>
+     * 
+     * <pre>
+     * ObjectUtils.toString(null, null)           = null
+     * ObjectUtils.toString(null, "null")         = "null"
+     * ObjectUtils.toString("", "null")           = ""
+     * ObjectUtils.toString("bat", "null")        = "bat"
+     * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
+     * </pre>
+     * 
+     * @see String#valueOf(Object)
+     * @param obj  the Object to <code>toString</code>, may be null
+     * @param nullStr  the String to return if <code>null</code> input, may be null
+     * @return the passed in Object's toString, or nullStr if <code>null</code> input
+     * @since 2.0
+     */
+    public static String toString(Object obj, String nullStr) {
+        return (obj == null ? nullStr : obj.toString());
+    }
+
+    // Null
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Class used as a null placeholder where <code>null</code>
+     * has another meaning.</p>
+     *
+     * <p>For example, in a <code>HashMap</code> the
+     * {@link java.util.HashMap#get(java.lang.Object)} method returns
+     * <code>null</code> if the <code>Map</code> contains
+     * <code>null</code> or if there is no matching key. The
+     * <code>Null</code> placeholder can be used to distinguish between
+     * these two cases.</p>
+     *
+     * <p>Another example is <code>Hashtable</code>, where <code>null</code>
+     * cannot be stored.</p>
+     */
+    public static class Null implements Serializable {
+        // declare serialization compatibility with Commons Lang 1.0
+        private static final long serialVersionUID = 7092611880189329093L;
+        
+        /**
+         * Restricted constructor - singleton.
+         */
+        Null() {
+        }
+        
+        /**
+         * <p>Ensure singleton.</p>
+         * 
+         * @return the singleton value
+         */
+        private Object readResolve() {
+            return ObjectUtils.NULL;
+        }
+    }
+    
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ReflectionToStringBuilder.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ReflectionToStringBuilder.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * <p>
+ * Assists in implementing {@link Object#toString()}methods using reflection.
+ * </p>
+ * 
+ * <p>
+ * This class uses reflection to determine the fields to append. Because these
+ * fields are usually private, the class uses
+ * {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)}
+ * to change the visibility of the fields. This will fail under a security
+ * manager, unless the appropriate permissions are set up correctly.
+ * </p>
+ * 
+ * <p>
+ * A typical invocation for this method would look like:
+ * </p>
+ * 
+ * <pre>
+ * public String toString() {
+ *   return ReflectionToStringBuilder.toString(this);
+ * }</pre>
+ * 
+ * 
+ * 
+ * <p>
+ * You can also use the builder to debug 3rd party objects:
+ * </p>
+ * 
+ * <pre>
+ * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));</pre>
+ * 
+ * 
+ * 
+ * <p>
+ * A subclass can control field output by overriding the methods:
+ * <ul>
+ * <li>{@link #accept(java.lang.reflect.Field)}</li>
+ * <li>{@link #getValue(java.lang.reflect.Field)}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * For example, this method does <i>not</i> include the <code>password</code>
+ * field in the returned <code>String</code>:
+ * </p>
+ * 
+ * <pre>
+ * public String toString() {
+ *     return (new ReflectionToStringBuilder(this) {
+ *         protected boolean accept(Field f) {
+ *             return super.accept(f) && !f.getName().equals("password");
+ *         }
+ *     }).toString();
+ * }</pre>
+ * 
+ * 
+ * 
+ * <p>
+ * The exact format of the <code>toString</code> is determined by the
+ * {@link ToStringStyle} passed into the constructor.
+ * </p>
+ * 
+ * @author Gary Gregory
+ * @author Stephen Colebourne
+ * @author Pete Gieser
+ * @since 2.0
+ * @version $Id: ReflectionToStringBuilder.java,v 1.15 2003/12/02 19:11:58
+ *               ggregory Exp $
+ */
+public class ReflectionToStringBuilder extends ToStringBuilder {
+    /**
+     * <p>
+     * A registry of objects used by <code>reflectionToString</code> methods
+     * to detect cyclical object references and avoid infinite loops.
+     * </p>
+     */
+    private static ThreadLocal registry = new ThreadLocal() {
+        protected synchronized Object initialValue() {
+            // The HashSet implementation is not synchronized,
+            // which is just what we need here.
+            return new HashSet();
+        }
+    };
+
+    /**
+     * <p>
+     * Returns the registry of objects being traversed by the <code>reflectionToString</code>
+     * methods in the current thread.
+     * </p>
+     * 
+     * @return Set the registry of objects being traversed
+     */
+    static Set getRegistry() {
+        return (Set) registry.get();
+    }
+
+    /**
+     * <p>
+     * Returns <code>true</code> if the registry contains the given object.
+     * Used by the reflection methods to avoid infinite loops.
+     * </p>
+     * 
+     * @param value
+     *                  The object to lookup in the registry.
+     * @return boolean <code>true</code> if the registry contains the given
+     *             object.
+     */
+    static boolean isRegistered(Object value) {
+        return getRegistry().contains(value);
+    }
+
+    /**
+     * <p>
+     * Registers the given object. Used by the reflection methods to avoid
+     * infinite loops.
+     * </p>
+     * 
+     * @param value
+     *                  The object to register.
+     */
+    static void register(Object value) {
+        getRegistry().add(value);
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>
+     * using the default <code>ToStringStyle</code>.
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * Transient members will be not be included, as they are likely derived.
+     * Static fields will not be included. Superclass fields will be appended.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to be output
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object is <code>null</code>
+     */
+    public static String toString(Object object) {
+        return toString(object, null, false, false, null);
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>.
+     * </p>
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * Transient members will be not be included, as they are likely derived.
+     * Static fields will not be included. Superclass fields will be appended.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default <code>ToStringStyle</code>
+     * is used.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to be output
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object or <code>ToStringStyle</code> is <code>null</code>
+     */
+    public static String toString(Object object, ToStringStyle style) {
+        return toString(object, style, false, false, null);
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>.
+     * </p>
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputTransients</code> is <code>true</code>,
+     * transient members will be output, otherwise they are ignored, as they
+     * are likely derived fields, and not part of the value of the Object.
+     * </p>
+     * 
+     * <p>
+     * Static fields will not be included. Superclass fields will be appended.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default <code>ToStringStyle</code>
+     * is used.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to be output
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object is <code>null</code>
+     */
+    public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
+        return toString(object, style, outputTransients, false, null);
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>.
+     * </p>
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputTransients</code> is <code>true</code>,
+     * transient fields will be output, otherwise they are ignored, as they are
+     * likely derived fields, and not part of the value of the Object.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputStatics</code> is <code>true</code>, static
+     * fields will be output, otherwise they are ignored.
+     * </p>
+     * 
+     * <p>
+     * Static fields will not be included. Superclass fields will be appended.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default <code>ToStringStyle</code>
+     * is used.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to be output
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     * @param outputStatics
+     *                  whether to include transient fields
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object is <code>null</code>
+     */
+    public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
+        return toString(object, style, outputTransients, outputStatics, null);
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>.
+     * </p>
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputTransients</code> is <code>true</code>,
+     * transient fields will be output, otherwise they are ignored, as they are
+     * likely derived fields, and not part of the value of the Object.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputStatics</code> is <code>true</code>, static
+     * fields will be output, otherwise they are ignored.
+     * </p>
+     * 
+     * <p>
+     * Superclass fields will be appended up to and including the specified
+     * superclass. A null superclass is treated as <code>java.lang.Object</code>.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default <code>ToStringStyle</code>
+     * is used.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to be output
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     * @param outputStatics
+     *                  whether to include static fields
+     * @param reflectUpToClass
+     *                  the superclass to reflect up to (inclusive), may be <code>null</code>
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object is <code>null</code>
+     */
+    public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics,
+            Class reflectUpToClass) {
+        return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics)
+                .toString();
+    }
+
+    /**
+     * <p>
+     * This method uses reflection to build a suitable <code>toString</code>.
+     * </p>
+     * 
+     * <p>
+     * It uses <code>AccessibleObject.setAccessible</code> to gain access to
+     * private fields. This means that it will throw a security exception if
+     * run under a security manager, if the permissions are not set up
+     * correctly. It is also not as efficient as testing explicitly.
+     * </p>
+     * 
+     * <p>
+     * If the <code>outputTransients</code> is <code>true</code>,
+     * transient members will be output, otherwise they are ignored, as they
+     * are likely derived fields, and not part of the value of the Object.
+     * </p>
+     * 
+     * <p>
+     * Static fields will not be included. Superclass fields will be appended
+     * up to and including the specified superclass. A null superclass is
+     * treated as <code>java.lang.Object</code>.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default <code>ToStringStyle</code>
+     * is used.
+     * </p>
+     * 
+     * @deprecated Use
+     *                     {@link #toString(Object,ToStringStyle,boolean,boolean,Class)}
+     * 
+     * @param object
+     *                  the Object to be output
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     * @param reflectUpToClass
+     *                  the superclass to reflect up to (inclusive), may be <code>null</code>
+     * @return the String result
+     * @throws IllegalArgumentException
+     *                  if the Object is <code>null</code>
+     */
+    public static String toString(Object object, ToStringStyle style, boolean outputTransients, Class reflectUpToClass) {
+        return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients).toString();
+    }
+
+    /**
+     * <p>
+     * Unregisters the given object.
+     * </p>
+     * 
+     * <p>
+     * Used by the reflection methods to avoid infinite loops.
+     * </p>
+     * 
+     * @param value
+     *                  The object to unregister.
+     */
+    static void unregister(Object value) {
+        getRegistry().remove(value);
+    }
+
+    /**
+     * Whether or not to append static fields.
+     */
+    private boolean appendStatics = false;
+
+    /**
+     * Whether or not to append transient fields.
+     */
+    private boolean appendTransients = false;
+
+    /**
+     * The last super class to stop appending fields for.
+     */
+    private Class upToClass = null;
+
+    /**
+     * <p>
+     * Constructor.
+     * </p>
+     * 
+     * <p>
+     * This constructor outputs using the default style set with <code>setDefaultStyle</code>.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to build a <code>toString</code> for, must not
+     *                  be <code>null</code>
+     * @throws IllegalArgumentException
+     *                  if the Object passed in is <code>null</code>
+     */
+    public ReflectionToStringBuilder(Object object) {
+        super(object);
+    }
+
+    /**
+     * <p>
+     * Constructor.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default style is used.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to build a <code>toString</code> for, must not
+     *                  be <code>null</code>
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @throws IllegalArgumentException
+     *                  if the Object passed in is <code>null</code>
+     */
+    public ReflectionToStringBuilder(Object object, ToStringStyle style) {
+        super(object, style);
+    }
+
+    /**
+     * <p>
+     * Constructor.
+     * </p>
+     * 
+     * <p>
+     * If the style is <code>null</code>, the default style is used.
+     * </p>
+     * 
+     * <p>
+     * If the buffer is <code>null</code>, a new one is created.
+     * </p>
+     * 
+     * @param object
+     *                  the Object to build a <code>toString</code> for
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param buffer
+     *                  the <code>StringBuffer</code> to populate, may be <code>null</code>
+     * @throws IllegalArgumentException
+     *                  if the Object passed in is <code>null</code>
+     */
+    public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
+        super(object, style, buffer);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @deprecated Use
+     *                     {@link #ReflectionToStringBuilder(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)}.
+     * 
+     * @param object
+     *                  the Object to build a <code>toString</code> for
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param buffer
+     *                  the <code>StringBuffer</code> to populate, may be <code>null</code>
+     * @param reflectUpToClass
+     *                  the superclass to reflect up to (inclusive), may be <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     */
+    public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
+            boolean outputTransients) {
+        super(object, style, buffer);
+        this.setUpToClass(reflectUpToClass);
+        this.setAppendTransients(outputTransients);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param object
+     *                  the Object to build a <code>toString</code> for
+     * @param style
+     *                  the style of the <code>toString</code> to create, may be
+     *                  <code>null</code>
+     * @param buffer
+     *                  the <code>StringBuffer</code> to populate, may be <code>null</code>
+     * @param reflectUpToClass
+     *                  the superclass to reflect up to (inclusive), may be <code>null</code>
+     * @param outputTransients
+     *                  whether to include transient fields
+     * @param outputStatics
+     *                  whether to include static fields
+     */
+    public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
+            boolean outputTransients, boolean outputStatics) {
+        super(object, style, buffer);
+        this.setUpToClass(reflectUpToClass);
+        this.setAppendTransients(outputTransients);
+        this.setAppendStatics(outputStatics);
+    }
+
+    /**
+     * Returns whether or not to append the given <code>Field</code>.
+     * <ul>
+     * <li>Transient fields are appended only if {@link #isAppendTransients()}
+     * returns <code>true</code>.
+     * <li>Static fields are appended only if {@link #isAppendStatics()}
+     * returns <code>true</code>.
+     * <li>Inner class fields are not appened.</li>
+     * </ul>
+     * 
+     * @param field
+     *                  The Field to test.
+     * @return Whether or not to append the given <code>Field</code>.
+     */
+    protected boolean accept(Field field) {
+        if (field.getName().indexOf('$') != -1) {
+            // Reject field from inner class.
+            return false;
+        }
+        if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
+            // transients.
+            return false;
+        }
+        if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
+            // transients.
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * <p>
+     * Appends the fields and values defined by the given object of the given
+     * Class.
+     * </p>
+     * 
+     * <p>
+     * If a cycle is detected as an object is &quot;toString()'ed&quot;, such
+     * an object is rendered as if <code>Object.toString()</code> had been
+     * called and not implemented by the object.
+     * </p>
+     * 
+     * @param clazz
+     *                  The class of object parameter
+     */
+    protected void appendFieldsIn(Class clazz) {
+        if (isRegistered(this.getObject())) {
+            // The object has already been appended, therefore we have an
+            // object cycle.
+            // Append a simple Object.toString style string. The field name is
+            // already appended at this point.
+            this.appendAsObjectToString(this.getObject());
+            return;
+        }
+        try {
+            this.registerObject();
+            if (clazz.isArray()) {
+                this.reflectionAppendArray(this.getObject());
+                return;
+            }
+            Field[] fields = clazz.getDeclaredFields();
+            AccessibleObject.setAccessible(fields, true);
+            for (int i = 0; i < fields.length; i++) {
+                Field field = fields[i];
+                String fieldName = field.getName();
+                if (this.accept(field)) {
+                    try {
+                        // Warning: Field.get(Object) creates wrappers objects
+                        // for primitive types.
+                        Object fieldValue = this.getValue(field);
+                        if (isRegistered(fieldValue) && !field.getType().isPrimitive()) {
+                            // A known field value has already been appended,
+                            // therefore we have an object cycle,
+                            // append a simple Object.toString style string.
+                            this.getStyle().appendFieldStart(this.getStringBuffer(), fieldName);
+                            this.appendAsObjectToString(fieldValue);
+                            // The recursion out of
+                            //    builder.append(fieldName, fieldValue);
+                            // below will append the field
+                            // end marker.
+                        } else {
+                            try {
+                                this.registerObject();
+                                this.append(fieldName, fieldValue);
+                            } finally {
+                                this.unregisterObject();
+                            }
+                        }
+                    } catch (IllegalAccessException ex) {
+                        //this can't happen. Would get a Security exception
+                        // instead
+                        //throw a runtime exception in case the impossible
+                        // happens.
+                        throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage());
+                    }
+                }
+            }
+        } finally {
+            this.unregisterObject();
+        }
+    }
+
+    /**
+     * <p>
+     * Gets the last super class to stop appending fields for.
+     * </p>
+     * 
+     * @return The last super class to stop appending fields for.
+     */
+    public Class getUpToClass() {
+        return this.upToClass;
+    }
+
+    /**
+     * <p>
+     * Calls <code>java.lang.reflect.Field.get(Object)</code>.
+     * </p>
+     * 
+     * @param field
+     *                  The Field to query.
+     * @return The Object from the given Field.
+     * 
+     * @throws IllegalArgumentException
+     *                  see {@link java.lang.reflect.Field#get(Object)}
+     * @throws IllegalAccessException
+     *                  see {@link java.lang.reflect.Field#get(Object)}
+     * 
+     * @see java.lang.reflect.Field#get(Object)
+     */
+    protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException {
+        return field.get(this.getObject());
+    }
+
+    /**
+     * <p>
+     * Gets whether or not to append static fields.
+     * </p>
+     * 
+     * @return Whether or not to append static fields.
+     */
+    public boolean isAppendStatics() {
+        return this.appendStatics;
+    }
+
+    /**
+     * <p>
+     * Gets whether or not to append transient fields.
+     * </p>
+     * 
+     * @return Whether or not to append transient fields.
+     */
+    public boolean isAppendTransients() {
+        return this.appendTransients;
+    }
+
+    /**
+     * <p>
+     * Append to the <code>toString</code> an <code>Object</code> array.
+     * </p>
+     * 
+     * @param array
+     *                  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder reflectionAppendArray(Object array) {
+        this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
+        return this;
+    }
+
+    /**
+     * <p>
+     * Registers this builder's source object to avoid infinite loops when
+     * processing circular object references.
+     * </p>
+     */
+    void registerObject() {
+        register(this.getObject());
+    }
+
+    /**
+     * <p>
+     * Sets whether or not to append static fields.
+     * </p>
+     * 
+     * @param appendStatics
+     *                  Whether or not to append static fields.
+     */
+    public void setAppendStatics(boolean appendStatics) {
+        this.appendStatics = appendStatics;
+    }
+
+    /**
+     * <p>
+     * Sets whether or not to append transient fields.
+     * </p>
+     * 
+     * @param appendTransients
+     *                  Whether or not to append transient fields.
+     */
+    public void setAppendTransients(boolean appendTransients) {
+        this.appendTransients = appendTransients;
+    }
+
+    /**
+     * <p>
+     * Sets the last super class to stop appending fields for.
+     * </p>
+     * 
+     * @param clazz
+     *                  The last super class to stop appending fields for.
+     */
+    public void setUpToClass(Class clazz) {
+        this.upToClass = clazz;
+    }
+
+    /**
+     * <p>
+     * Gets the String built by this builder.
+     * </p>
+     * 
+     * @return the built string
+     */
+    public String toString() {
+        if (this.getObject() == null) {
+            return this.getStyle().getNullText();
+        }
+        Class clazz = this.getObject().getClass();
+        this.appendFieldsIn(clazz);
+        while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) {
+            clazz = clazz.getSuperclass();
+            this.appendFieldsIn(clazz);
+        }
+        return super.toString();
+    }
+
+    /**
+     * <p>
+     * Unregisters this builder's source object to avoid infinite loops when
+     * processing circular object references.
+     * </p>
+     */
+    void unregisterObject() {
+        unregister(this.getObject());
+    }
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/SystemUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/SystemUtils.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,1296 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.io.File;
+
+/**
+ * <p>Helpers for <code>java.lang.System</code>.</p>
+ * 
+ * <p>If a system property cannot be read due to security restrictions, 
+ * the corresponding field in this class will be set to <code>null</code>
+ * and a message will be written to <code>System.err</code>.</p>
+ *
+ * @author Based on code from Avalon Excalibur
+ * @author Based on code from Lucene
+ * @author Stephen Colebourne
+ * @author <a href="mailto:sdowney@panix.com">Steve Downey</a>
+ * @author Gary Gregory
+ * @author Michael Becke
+ * @author Tetsuya Kaneuchi
+ * @author Rafal Krupinski
+ * @since 1.0
+ * @version $Id: SystemUtils.java,v 1.35 2004/08/30 21:21:18 ggregory Exp $
+ */
+public class SystemUtils {
+
+    /**
+     * The prefix String for all Windows OS.
+     */
+    private static final String OS_NAME_WINDOWS_PREFIX = "Windows";
+    
+    // System property constants
+    //-----------------------------------------------------------------------
+    // These MUST be declared first. Other constants depend on this.
+    
+    /**
+     * The System property key for the user home directory.
+     */
+    private static final String USER_HOME_KEY = "user.home";
+
+    /**
+     * The System property key for the user directory.
+     */
+    private static final String USER_DIR_KEY = "user.dir";
+    
+    /**
+     * The System property key for the Java IO temporary directory.
+     */
+    private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir";
+    
+    /**
+     * The System property key for the Java home directory.
+     */
+    private static final String JAVA_HOME_KEY = "java.home";
+    
+    /**
+     * <p>The <code>awt.toolkit</code> System Property.</p>
+     * <p>Holds a class name, on Windows XP this is <code>sun.awt.windows.WToolkit</code>.</p>
+     * <p><b>On platforms without a GUI, this value is <code>null</code>.</b></p>
+     * 
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     */
+    public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit");
+
+    /**
+     * <p>The <code>file.encoding</code> System Property.</p>
+     * <p>File encoding, such as <code>Cp1252</code>.</p>
+     * 
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.2
+     */
+    public static final String FILE_ENCODING = getSystemProperty("file.encoding");
+
+    /**
+     * <p>The <code>file.separator</code> System Property.
+     * File separator (<code>&quot;/&quot;</code> on UNIX).</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String FILE_SEPARATOR = getSystemProperty("file.separator");
+
+    /**
+     * <p>The <code>java.awt.fonts</code> System Property.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     */
+    public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts");
+
+    /**
+     * <p>The <code>java.awt.graphicsenv</code> System Property.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     */
+    public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv");
+
+    /**
+     * <p>
+     * The <code>java.awt.headless</code> System Property.
+     * The value of this property is the String <code>"true"</code> or <code>"false"</code>. 
+     * </p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @see #isJavaAwtHeadless()
+     * @since 2.1
+     * @since Java 1.4
+     */
+    public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless");
+
+    /**
+     * <p>The <code>java.awt.printerjob</code> System Property.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     */
+    public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob");
+
+    /**
+     * <p>The <code>java.class.path</code> System Property. Java class path.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path");
+
+    /**
+     * <p>The <code>java.class.version</code> System Property.
+     * Java class format version number.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version");
+
+    /**
+     * <p>The <code>java.compiler</code> System Property. Name of JIT compiler to use.
+     * First in JDK version 1.2. Not used in Sun JDKs after 1.2.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2. Not used in Sun versions after 1.2.
+     */
+    public static final String JAVA_COMPILER = getSystemProperty("java.compiler");
+
+    /**
+     * <p>The <code>java.endorsed.dirs</code> System Property. Path of endorsed directory
+     * or directories.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.4
+     */
+    public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs");
+
+    /**
+     * <p>The <code>java.ext.dirs</code> System Property. Path of extension directory
+     * or directories.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.3
+     */
+    public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs");
+
+    /**
+     * <p>The <code>java.home</code> System Property. Java installation directory.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY);
+
+    /**
+     * <p>The <code>java.io.tmpdir</code> System Property. Default temp file path.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY);
+
+    /**
+     * <p>The <code>java.library.path</code> System Property. List of paths to search
+     * when loading libraries.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path");
+
+    /**
+     * <p>The <code>java.runtime.name</code> System Property. Java Runtime Environment
+     * name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.3
+     */
+    public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name");
+
+    /**
+     * <p>The <code>java.runtime.version</code> System Property. Java Runtime Environment
+     * version.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.3
+     */
+    public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version");
+
+    /**
+     * <p>The <code>java.specification.name</code> System Property. Java Runtime Environment
+     * specification name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name");
+
+    /**
+     * <p>The <code>java.specification.vendor</code> System Property. Java Runtime Environment
+     * specification vendor.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor");
+
+    /**
+     * <p>The <code>java.specification.version</code> System Property. Java Runtime Environment
+     * specification version.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.3
+     */
+    public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version");
+
+    /**
+     * <p>The <code>java.util.prefs.PreferencesFactory</code> System Property. A class name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     * @since Java 1.4
+     */
+    public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY = getSystemProperty("java.util.prefs.PreferencesFactory");
+
+    /**
+     * <p>The <code>java.vendor</code> System Property. Java vendor-specific string.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String JAVA_VENDOR = getSystemProperty("java.vendor");
+
+    /**
+     * <p>The <code>java.vendor.url</code> System Property. Java vendor URL.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+    */
+    public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url");
+
+    /**
+     * <p>The <code>java.version</code> System Property. Java version number.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String JAVA_VERSION = getSystemProperty("java.version");
+
+    /**
+     * <p>The <code>java.vm.info</code> System Property. Java Virtual Machine implementation
+     * info.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info");
+
+    /**
+     * <p>The <code>java.vm.name</code> System Property. Java Virtual Machine implementation
+     * name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name");
+
+    /**
+     * <p>The <code>java.vm.specification.name</code> System Property. Java Virtual Machine
+     * specification name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name");
+
+    /**
+     * <p>The <code>java.vm.specification.vendor</code> System Property. Java Virtual
+     * Machine specification vendor.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor");
+
+    /**
+     * <p>The <code>java.vm.specification.version</code> System Property. Java Virtual Machine
+     * specification version.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version");
+
+    /**
+     * <p>The <code>java.vm.vendor</code> System Property. Java Virtual Machine implementation
+     * vendor.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor");
+
+    /**
+     * <p>The <code>java.vm.version</code> System Property. Java Virtual Machine
+     * implementation version.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.2
+     */
+    public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version");
+
+    /**
+     * <p>The <code>line.separator</code> System Property. Line separator
+     * (<code>&quot;\n<&quot;</code> on UNIX).</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String LINE_SEPARATOR = getSystemProperty("line.separator");
+
+    /**
+     * <p>The <code>os.arch</code> System Property. Operating system architecture.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String OS_ARCH = getSystemProperty("os.arch");
+
+    /**
+     * <p>The <code>os.name</code> System Property. Operating system name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String OS_NAME = getSystemProperty("os.name");
+
+    /**
+     * <p>The <code>os.version</code> System Property. Operating system version.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String OS_VERSION = getSystemProperty("os.version");
+
+    /**
+     * <p>The <code>path.separator</code> System Property. Path separator
+     * (<code>&quot;:&quot;</code> on UNIX).</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String PATH_SEPARATOR = getSystemProperty("path.separator");
+
+    /**
+     * <p>The <code>user.country</code> or <code>user.region</code> System Property.
+     * User's country code, such as <code>GB</code>. First in JDK version 1.2 as
+     * <code>user.region</code>. Renamed to <code>user.country</code> in 1.4</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.2
+     */
+    public static final String USER_COUNTRY = 
+        (getSystemProperty("user.country") == null ?
+            getSystemProperty("user.region") : getSystemProperty("user.country"));
+
+    /**
+     * <p>The <code>user.dir</code> System Property. User's current working
+     * directory.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String USER_DIR = getSystemProperty(USER_DIR_KEY);
+
+    /**
+     * <p>The <code>user.home</code> System Property. User's home directory.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String USER_HOME = getSystemProperty(USER_HOME_KEY);
+
+    /**
+     * <p>The <code>user.language</code> System Property. User's language code,
+     * such as <code>"en"</code>.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.0
+     * @since Java 1.2
+     */
+    public static final String USER_LANGUAGE = getSystemProperty("user.language");
+
+    /**
+     * <p>The <code>user.name</code> System Property. User's account name.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since Java 1.1
+     */
+    public static final String USER_NAME = getSystemProperty("user.name");
+
+    /**
+     * <p>The <code>user.timezone</code> System Property. 
+     * For example: <code>"America/Los_Angeles"</code>.</p>
+     *
+     * <p>Defaults to <code>null</code> if the runtime does not have
+     * security access to read this property or the property does not exist.</p>
+     * 
+     * <p>
+     * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)}
+     * or {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value
+     * will be out of sync with that System property.
+     * </p>
+     * 
+     * @since 2.1
+     */
+    public static final String USER_TIMEZONE = getSystemProperty("user.timezone");
+
+    // Java version
+    //-----------------------------------------------------------------------
+    // These MUST be declared after those above as they depend on the
+    // values being set up
+    
+    /**
+     * <p>Gets the Java version as a <code>float</code>.</p>
+     *
+     * <p>Example return values:</p>
+     * <ul>
+     *  <li><code>1.2f</code> for JDK 1.2
+     *  <li><code>1.31f</code> for JDK 1.3.1
+     * </ul>
+     *
+     * <p>The field will return zero if {@link #JAVA_VERSION} is <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final float JAVA_VERSION_FLOAT = getJavaVersionAsFloat();
+
+    /**
+     * <p>Gets the Java version as an <code>int</code>.</p>
+     *
+     * <p>Example return values:</p>
+     * <ul>
+     *  <li><code>120</code> for JDK 1.2
+     *  <li><code>131</code> for JDK 1.3.1
+     * </ul>
+     *
+     * <p>The field will return zero if {@link #JAVA_VERSION} is <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final int JAVA_VERSION_INT = getJavaVersionAsInt();
+
+    // Java version checks
+    //-----------------------------------------------------------------------
+    // These MUST be declared after those above as they depend on the
+    // values being set up
+    
+    /**
+     * <p>Is <code>true</code> if this is Java version 1.1 (also 1.1.x versions).</p>
+     *
+     * <p>The field will return <code>false</code> if {@link #JAVA_VERSION} is
+     * <code>null</code>.</p>
+     */
+    public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1");
+
+    /**
+     * <p>Is <code>true</code> if this is Java version 1.2 (also 1.2.x versions).</p>
+     *
+     * <p>The field will return <code>false</code> if {@link #JAVA_VERSION} is
+     * <code>null</code>.</p>
+     */
+    public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2");
+
+    /**
+     * <p>Is <code>true</code> if this is Java version 1.3 (also 1.3.x versions).</p>
+     *
+     * <p>The field will return <code>false</code> if {@link #JAVA_VERSION} is
+     * <code>null</code>.</p>
+     */
+    public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3");
+
+    /**
+     * <p>Is <code>true</code> if this is Java version 1.4 (also 1.4.x versions).</p>
+     *
+     * <p>The field will return <code>false</code> if {@link #JAVA_VERSION} is
+     * <code>null</code>.</p>
+     */
+    public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4");
+
+    /**
+     * <p>Is <code>true</code> if this is Java version 1.5 (also 1.5.x versions).</p>
+     *
+     * <p>The field will return <code>false</code> if {@link #JAVA_VERSION} is
+     * <code>null</code>.</p>
+     */
+    public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5");
+
+    // Operating system checks
+    //-----------------------------------------------------------------------
+    // These MUST be declared after those above as they depend on the
+    // values being set up
+    // OS names from http://www.vamphq.com/os.html
+    // Selected ones included - please advise commons-dev@jakarta.apache.org
+    // if you want another added or a mistake corrected
+
+    /**
+     * <p>Is <code>true</code> if this is AIX.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_AIX = getOSMatches("AIX");
+
+    /**
+     * <p>Is <code>true</code> if this is HP-UX.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_HP_UX = getOSMatches("HP-UX");
+
+    /**
+     * <p>Is <code>true</code> if this is Irix.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_IRIX = getOSMatches("Irix");
+
+    /**
+     * <p>Is <code>true</code> if this is Linux.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_LINUX = getOSMatches("Linux") || getOSMatches("LINUX");
+
+    /**
+     * <p>Is <code>true</code> if this is Mac.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_MAC = getOSMatches("Mac");
+
+    /**
+     * <p>Is <code>true</code> if this is Mac.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_MAC_OSX = getOSMatches("Mac OS X");
+
+    /**
+     * <p>Is <code>true</code> if this is OS/2.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_OS2 = getOSMatches("OS/2");
+
+    /**
+     * <p>Is <code>true</code> if this is Solaris.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_SOLARIS = getOSMatches("Solaris");
+
+    /**
+     * <p>Is <code>true</code> if this is SunOS.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_SUN_OS = getOSMatches("SunOS");
+
+    /**
+     * <p>Is <code>true</code> if this is a POSIX compilant system,
+     * as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.1
+     */
+    public static final boolean IS_OS_UNIX =
+        IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX ||
+        IS_OS_MAC_OSX || IS_OS_SOLARIS || IS_OS_SUN_OS;
+
+    /**
+     * <p>Is <code>true</code> if this is Windows.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS = getOSMatches(OS_NAME_WINDOWS_PREFIX);
+
+    /**
+     * <p>Is <code>true</code> if this is Windows 2000.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0");
+
+    /**
+     * <p>Is <code>true</code> if this is Windows 95.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_95 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.0");
+    // JDK 1.2 running on Windows98 returns 'Windows 95', hence the above
+
+    /**
+     * <p>Is <code>true</code> if this is Windows 98.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_98 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.1");
+    // JDK 1.2 running on Windows98 returns 'Windows 95', hence the above
+
+    /**
+     * <p>Is <code>true</code> if this is Windows ME.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_ME = getOSMatches(OS_NAME_WINDOWS_PREFIX, "4.9");
+    // JDK 1.2 running on WindowsME may return 'Windows 95', hence the above
+
+    /**
+     * <p>Is <code>true</code> if this is Windows NT.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_NT = getOSMatches(OS_NAME_WINDOWS_PREFIX + " NT");
+    // Windows 2000 returns 'Windows 2000' but may suffer from same JDK1.2 problem
+
+    /**
+     * <p>Is <code>true</code> if this is Windows XP.</p>
+     *
+     * <p>The field will return <code>false</code> if <code>OS_NAME</code> is
+     * <code>null</code>.</p>
+     * 
+     * @since 2.0
+     */
+    public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1");
+
+    //-----------------------------------------------------------------------    
+    /**
+     * <p>SystemUtils instances should NOT be constructed in standard
+     * programming. Instead, the class should be used as
+     * <code>SystemUtils.FILE_SEPARATOR</code>.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean
+     * instance to operate.</p>
+     */
+    public SystemUtils() {
+        // no init.
+    }
+    
+    //-----------------------------------------------------------------------    
+    /**
+     * <p>Gets the Java version number as a <code>float</code>.</p>
+     *
+     * <p>Example return values:</p>
+     * <ul>
+     *  <li><code>1.2f</code> for JDK 1.2
+     *  <li><code>1.31f</code> for JDK 1.3.1
+     * </ul>
+     * 
+     * @return the version, for example 1.31f for JDK 1.3.1
+     * @deprecated Use {@link #JAVA_VERSION_FLOAT} instead.
+     *             Method will be removed in Commons Lang 3.0.
+     */
+    public static float getJavaVersion() {
+        return JAVA_VERSION_FLOAT;
+    }
+
+    /**
+     * <p>Gets the Java version number as a <code>float</code>.</p>
+     *
+     * <p>Example return values:</p>
+     * <ul>
+     *  <li><code>1.2f</code> for JDK 1.2
+     *  <li><code>1.31f</code> for JDK 1.3.1
+     * </ul>
+     * 
+     * <p>Patch releases are not reported.
+     * Zero is returned if {@link #JAVA_VERSION} is <code>null</code>.</p>
+     * 
+     * @return the version, for example 1.31f for JDK 1.3.1
+     */
+    private static float getJavaVersionAsFloat() {
+        if (JAVA_VERSION == null) {
+            return 0f;
+        }
+        String str = JAVA_VERSION.substring(0, 3);
+        if (JAVA_VERSION.length() >= 5) {
+            str = str + JAVA_VERSION.substring(4, 5);
+        }
+        return Float.parseFloat(str);
+    }
+    
+    /**
+     * <p>Gets the Java version number as an <code>int</code>.</p>
+     *
+     * <p>Example return values:</p>
+     * <ul>
+     *  <li><code>120</code> for JDK 1.2
+     *  <li><code>131</code> for JDK 1.3.1
+     * </ul>
+     * 
+     * <p>Patch releases are not reported.
+     * Zero is returned if {@link #JAVA_VERSION} is <code>null</code>.</p>
+     * 
+     * @return the version, for example 131 for JDK 1.3.1
+     */
+    private static int getJavaVersionAsInt() {
+        if (JAVA_VERSION == null) {
+            return 0;
+        }
+        String str = JAVA_VERSION.substring(0, 1);
+        str = str + JAVA_VERSION.substring(2, 3);
+        if (JAVA_VERSION.length() >= 5) {
+            str = str + JAVA_VERSION.substring(4, 5);
+        } else {
+            str = str + "0";
+        }
+        return Integer.parseInt(str);
+    }
+
+    /**
+     * <p>Decides if the java version matches.</p>
+     * 
+     * @param versionPrefix  the prefix for the java version
+     * @return true if matches, or false if not or can't determine
+     */
+    private static boolean getJavaVersionMatches(String versionPrefix) {
+        if (JAVA_VERSION == null) {
+            return false;
+        }
+        return JAVA_VERSION.startsWith(versionPrefix);
+    }    
+    
+    /**
+     * <p>Decides if the operating system matches.</p>
+     * 
+     * @param osNamePrefix  the prefix for the os name
+     * @return true if matches, or false if not or can't determine
+     */
+    private static boolean getOSMatches(String osNamePrefix) {
+        if (OS_NAME == null) {
+            return false;
+        }
+        return OS_NAME.startsWith(osNamePrefix);
+    }    
+
+    /**
+     * <p>Decides if the operating system matches.</p>
+     * 
+     * @param osNamePrefix  the prefix for the os name
+     * @param osVersionPrefix  the prefix for the version
+     * @return true if matches, or false if not or can't determine
+     */
+    private static boolean getOSMatches(String osNamePrefix, String osVersionPrefix) {
+        if (OS_NAME == null || OS_VERSION == null) {
+            return false;
+        }
+        return OS_NAME.startsWith(osNamePrefix) && OS_VERSION.startsWith(osVersionPrefix);
+    }    
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Gets a System property, defaulting to <code>null</code> if the property
+     * cannot be read.</p>
+     *
+     * <p>If a <code>SecurityException</code> is caught, the return
+     * value is <code>null</code> and a message is written to <code>System.err</code>.</p>
+     * 
+     * @param property the system property name
+     * @return the system property value or <code>null</code> if a security problem occurs
+     */
+    private static String getSystemProperty(String property) {
+        try {
+            return System.getProperty(property);
+        } catch (SecurityException ex) {
+            // we are not allowed to look at this property
+            System.err.println(
+                "Caught a SecurityException reading the system property '" + property 
+                + "'; the SystemUtils property value will default to null."
+            );
+            return null;
+        }
+    }
+    
+    /**
+     * <p>Is the Java version at least the requested version.</p>
+     *
+     * <p>Example input:</p>
+     * <ul>
+     *  <li><code>1.2f</code> to test for JDK 1.2</li>
+     *  <li><code>1.31f</code> to test for JDK 1.3.1</li>
+     * </ul>
+     * 
+     * @param requiredVersion  the required version, for example 1.31f
+     * @return <code>true</code> if the actual version is equal or greater
+     *  than the required version
+     */
+    public static boolean isJavaVersionAtLeast(float requiredVersion) {
+        return (JAVA_VERSION_FLOAT >= requiredVersion);
+    }
+    
+    /**
+     * <p>Is the Java version at least the requested version.</p>
+     *
+     * <p>Example input:</p>
+     * <ul>
+     *  <li><code>120</code> to test for JDK 1.2 or greater</li>
+     *  <li><code>131</code> to test for JDK 1.3.1 or greater</li>
+     * </ul>
+     * 
+     * @param requiredVersion  the required version, for example 131
+     * @return <code>true</code> if the actual version is equal or greater
+     *  than the required version
+     * @since 2.0
+     */
+    public static boolean isJavaVersionAtLeast(int requiredVersion) {
+        return (JAVA_VERSION_INT >= requiredVersion);
+    }
+
+    /**
+     * Returns whether the {@link #JAVA_AWT_HEADLESS} value is <code>true</code>.
+     *  
+     * @return <code>true</code> if <code>JAVA_AWT_HEADLESS</code> is <code>"true"</code>,
+     * <code>false</code> otherwise.
+     * 
+     * @see #JAVA_AWT_HEADLESS
+     * @since 2.1
+     * @since Java 1.4
+     */
+    public static boolean isJavaAwtHeadless() {
+        return JAVA_AWT_HEADLESS != null ? JAVA_AWT_HEADLESS.equals(Boolean.TRUE.toString()) : false;
+    }
+    /**
+     * <p>Gets the Java home directory as a <code>File</code>.</p>
+     * 
+     * @return a directory
+     * @throws  SecurityException  if a security manager exists and its  
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @see System#getProperty(String)
+     */
+    public static File getJavaHome() {
+        return new File(System.getProperty(JAVA_HOME_KEY));
+    }
+
+    /**
+     * <p>Gets the Java IO temporary directory as a <code>File</code>.</p>
+     * 
+     * @return a directory
+     * @throws  SecurityException  if a security manager exists and its  
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @see System#getProperty(String)
+     */
+    public static File getJavaIoTmpDir() {
+        return new File(System.getProperty(JAVA_IO_TMPDIR_KEY));
+    }
+
+    /**
+     * <p>Gets the user directory as a <code>File</code>.</p>
+     * 
+     * @return a directory
+     * @throws  SecurityException  if a security manager exists and its  
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @see System#getProperty(String)
+     */
+    public static File getUserDir() {
+        return new File(System.getProperty(USER_DIR_KEY));
+    }
+
+    /**
+     * <p>Gets the user home directory as a <code>File</code>.</p>
+     * 
+     * @return a directory
+     * @throws  SecurityException  if a security manager exists and its  
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @see System#getProperty(String)
+     */
+    public static File getUserHome() {
+        return new File(System.getProperty(USER_HOME_KEY));
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringBuilder.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringBuilder.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,1041 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+
+/**
+ * <p>Assists in implementing {@link Object#toString()} methods.</p>
+ *
+ * <p>This class enables a good and consistent <code>toString()</code> to be built for any
+ * class or object. This class aims to simplify the process by:</p>
+ * <ul>
+ *  <li>allowing field names</li>
+ *  <li>handling all types consistently</li>
+ *  <li>handling nulls consistently</li>
+ *  <li>outputting arrays and multi-dimensional arrays</li>
+ *  <li>enabling the detail level to be controlled for Objects and Collections</li>
+ *  <li>handling class hierarchies</li>
+ * </ul>
+ *
+ * <p>To use this class write code as follows:</p>
+ *
+ * <pre>
+ * public class Person {
+ *   String name;
+ *   int age;
+ *   boolean isSmoker;
+ * 
+ *   ...
+ * 
+ *   public String toString() {
+ *     return new ToStringBuilder(this).
+ *       append("name", name).
+ *       append("age", age).
+ *       append("smoker", smoker).
+ *       toString();
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>This will produce a toString of the format:
+ * <code>Person@7f54[name=Stephen,age=29,smoker=false]</code></p>
+ * 
+ * <p>To add the superclass <code>toString</code>, use {@link #appendSuper}.
+ * To append the <code>toString</code> from an object that is delegated
+ * to (or any other object), use {@link #appendToString}.</p>
+ *
+ * <p>Alternatively, there is a method that uses reflection to determine
+ * the fields to test. Because these fields are usually private, the method, 
+ * <code>reflectionToString</code>, uses <code>AccessibleObject.setAccessible</code> to
+ * change the visibility of the fields. This will fail under a security manager,
+ * unless the appropriate permissions are set up correctly. It is also
+ * slower than testing explicitly.</p>
+ *
+ * <p>A typical invocation for this method would look like:</p>
+ *
+ * <pre>
+ * public String toString() {
+ *   return ToStringBuilder.reflectionToString(this);
+ * }
+ * </pre>
+ *
+ * <p>You can also use the builder to debug 3rd party objects:</p>
+ *
+ * <pre>
+ * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
+ * </pre>
+ * 
+ * <p>The exact format of the <code>toString</code> is determined by
+ * the {@link ToStringStyle} passed into the constructor.</p>
+ *
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Pete Gieser
+ * @since 1.0
+ * @version $Id: ToStringBuilder.java,v 1.35 2004/07/01 17:40:10 ggregory Exp $
+ */
+public class ToStringBuilder {
+
+    /**
+     * The default style of output to use.
+     */
+    private static ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE;
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Gets the default <code>ToStringStyle</code> to use.</p>
+     *
+     * <p>This could allow the <code>ToStringStyle</code> to be
+     * controlled for an entire application with one call.</p>
+     *
+     * <p>This might be used to have a verbose
+     * <code>ToStringStyle</code> during development and a compact
+     * <code>ToStringStyle</code> in production.</p>
+     * 
+     * @return the default <code>ToStringStyle</code>
+     */
+    public static ToStringStyle getDefaultStyle() {
+        return defaultStyle;
+    }
+
+    /**
+     * <p>Forwards to <code>ReflectionToStringBuilder</code>.</p>
+     * 
+     * @see ReflectionToStringBuilder#toString(Object)
+     */
+    public static String reflectionToString(Object object) {
+        return ReflectionToStringBuilder.toString(object);
+    }
+
+    /**
+     * <p>Forwards to <code>ReflectionToStringBuilder</code>.</p>
+     * 
+     * @see ReflectionToStringBuilder#toString(Object,ToStringStyle)
+     */
+    public static String reflectionToString(Object object, ToStringStyle style) {
+        return ReflectionToStringBuilder.toString(object, style);
+    }
+
+    /**
+     * <p>Forwards to <code>ReflectionToStringBuilder</code>.</p>
+     * 
+     * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
+     */
+    public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
+        return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
+    }
+
+    /**
+     * <p>Forwards to <code>ReflectionToStringBuilder</code>.</p>
+     * 
+     * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class)
+     * @since 2.0
+     */
+    public static String reflectionToString(
+        Object object,
+        ToStringStyle style,
+        boolean outputTransients,
+        Class reflectUpToClass) {
+        return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
+    }
+
+    /**
+     * <p>Sets the default <code>ToStringStyle</code> to use.</p>
+     * 
+     * @param style  the default <code>ToStringStyle</code>
+     * @throws IllegalArgumentException if the style is <code>null</code>
+     */
+    public static void setDefaultStyle(ToStringStyle style) {
+        if (style == null) {
+            throw new IllegalArgumentException("The style must not be null");
+        }
+        defaultStyle = style;
+    }
+
+    /**
+     * Current toString buffer.
+     */
+    private final StringBuffer buffer;
+
+    /**
+     * The object being output.
+     */
+    private final Object object;
+
+    /**
+     * The style of output to use.
+     */
+    private final ToStringStyle style;
+
+    /**
+     * <p>Constructor for <code>ToStringBuilder</code>.</p>
+     *
+     * <p>This constructor outputs using the default style set with
+     * <code>setDefaultStyle</code>.</p>
+     * 
+     * @param object  the Object to build a <code>toString</code> for
+     * @throws IllegalArgumentException  if the Object passed in is
+     *  <code>null</code>
+     */
+    public ToStringBuilder(Object object) {
+        this(object, getDefaultStyle(), null);
+    }
+
+    /**
+     * <p>Constructor for <code>ToStringBuilder</code> specifying the
+     * output style.</p>
+     *
+     * <p>If the style is <code>null</code>, the default style is used.</p>
+     * 
+     * @param object  the Object to build a <code>toString</code> for
+     * @param style  the style of the <code>toString</code> to create,
+     *  may be <code>null</code>
+     * @throws IllegalArgumentException  if the Object passed in is
+     *  <code>null</code>
+     */
+    public ToStringBuilder(Object object, ToStringStyle style) {
+        this(object, style, null);
+    }
+
+    /**
+     * <p>Constructor for <code>ToStringBuilder</code>.</p>
+     *
+     * <p>If the style is <code>null</code>, the default style is used.</p>
+     *
+     * <p>If the buffer is <code>null</code>, a new one is created.</p>
+     * 
+     * @param object  the Object to build a <code>toString</code> for
+     * @param style  the style of the <code>toString</code> to create,
+     *  may be <code>null</code>
+     * @param buffer  the <code>StringBuffer</code> to populate, may be
+     *  <code>null</code>
+     */
+    public ToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
+        if (style == null) {
+            style = getDefaultStyle();
+        }
+        if (buffer == null) {
+            buffer = new StringBuffer(512);
+        }
+        this.buffer = buffer;
+        this.style = style;
+        this.object = object;
+
+        style.appendStart(buffer, object);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(boolean value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(boolean[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(byte value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(byte[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(char value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(char[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(double value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(double[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(float value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(float[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(int value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(int[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(long value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(long[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value.</p>
+     *
+     * @param object  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(Object object) {
+        style.append(buffer, null, object, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(Object[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * value.</p>
+     *
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(short value) {
+        style.append(buffer, null, value);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * array.</p>
+     *
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(short[] array) {
+        style.append(buffer, null, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, boolean value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>hashCode</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, boolean[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, boolean[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>byte</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, byte value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code> array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, byte[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, byte[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, char value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, char[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, char[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, double value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, double[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, double[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>float</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, float value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, float[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, float[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, int value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, int[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, int[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, long value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, long[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, long[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param object  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, Object object) {
+        style.append(buffer, fieldName, object, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param object  the value to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail,
+     *  <code>false</code> for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, Object object, boolean fullDetail) {
+        style.append(buffer, fieldName, object, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, Object[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, Object[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>short</code>
+     * value.</p>
+     *
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, short value) {
+        style.append(buffer, fieldName, value);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * array.</p>
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, short[] array) {
+        style.append(buffer, fieldName, array, null);
+        return this;
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * array.</p>
+     *
+     * <p>A boolean parameter controls the level of detail to show.
+     * Setting <code>true</code> will output the array in full. Setting
+     * <code>false</code> will output a summary, typically the size of
+     * the array.
+     *
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info
+     * @return this
+     */
+    public ToStringBuilder append(String fieldName, short[] array, boolean fullDetail) {
+        style.append(buffer, fieldName, array, BooleanUtils.toBooleanObject(fullDetail));
+        return this;
+    }
+
+    /**
+     * <p>Appends with the same format as the default <code>Object toString()
+     * </code> method. Appends the class name followed by 
+     * {@link System#identityHashCode(java.lang.Object)}.</p>
+     * 
+     * @param object  the <code>Object</code> whose class name and id to output
+     * @return this
+     * @since 2.0
+     */
+    public ToStringBuilder appendAsObjectToString(Object object) {
+        ObjectUtils.appendIdentityToString(this.getStringBuffer(), object);
+        return this;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append the <code>toString</code> from the superclass.</p>
+     * 
+     * <p>This method assumes that the superclass uses the same <code>ToStringStyle</code>
+     * as this one.</p>
+     * 
+     * <p>If <code>superToString</code> is <code>null</code>, no change is made.</p>
+     *
+     * @param superToString  the result of <code>super.toString()</code>
+     * @return this
+     * @since 2.0
+     */
+    public ToStringBuilder appendSuper(String superToString) {
+        if (superToString != null) {
+            style.appendSuper(buffer, superToString);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Append the <code>toString</code> from another object.</p>
+     * 
+     * <p>This method is useful where a class delegates most of the implementation of
+     * its properties to another class. You can then call <code>toString()</code> on
+     * the other class and pass the result into this method.</p>
+     * 
+     * <pre>
+     *   private AnotherObject delegate;
+     *   private String fieldInThisClass;
+     * 
+     *   public String toString() {
+     *     return new ToStringBuilder(this).
+     *       appendToString(delegate.toString()).
+     *       append(fieldInThisClass).
+     *       toString();
+     *   }</pre>
+     * 
+     * <p>This method assumes that the other object uses the same <code>ToStringStyle</code>
+     * as this one.</p>
+     * 
+     * <p>If the <code>toString</code> is <code>null</code>, no change is made.</p>
+     *
+     * @param toString  the result of <code>toString()</code> on another object
+     * @return this
+     * @since 2.0
+     */
+    public ToStringBuilder appendToString(String toString) {
+        if (toString != null) {
+            style.appendToString(buffer, toString);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Returns the <code>Object</code> being output.</p>
+     * 
+     * @return The object being output.
+     * @since 2.0
+     */
+    public Object getObject() {
+        return object;
+    }
+
+    /**
+     * <p>Gets the <code>StringBuffer</code> being populated.</p>
+     * 
+     * @return the <code>StringBuffer</code> being populated
+     */
+    public StringBuffer getStringBuffer() {
+        return buffer;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Gets the <code>ToStringStyle</code> being used.</p>
+     * 
+     * @return the <code>ToStringStyle</code> being used
+     * @since 2.0
+     */
+    public ToStringStyle getStyle() {
+        return style;
+    }
+
+    /**
+     * <p>Returns the built <code>toString</code>.</p>
+     * 
+     * <p>This method appends the end of data indicator, and can only be called once.
+     * Use {@link #getStringBuffer} to get the current string state.</p>
+     * 
+     * <p>If the object is <code>null</code>, return the style's <code>nullText</code></p>
+     * 
+     * @return the String <code>toString</code>
+     */
+    public String toString() {
+        if (this.getObject() == null) {
+            this.getStringBuffer().append(this.getStyle().getNullText());
+        } else {
+            style.appendEnd(this.getStringBuffer(), this.getObject());
+        }
+        return this.getStringBuffer().toString();
+    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringStyle.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ToStringStyle.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,2186 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Map;
+
+
+/**
+ * <p>Controls <code>String</code> formatting for {@link ToStringBuilder}.
+ * The main public interface is always via <code>ToStringBuilder</code>.</p>
+ *
+ * <p>These classes are intended to be used as <code>Singletons</code>.
+ * There is no need to instantiate a new style each time. A program
+ * will generally use one of the predefined constants on this class.
+ * Alternatively, the {@link } class can be used
+ * to set the individual settings. Thus most styles can be achieved
+ * without subclassing.</p>
+ *
+ * <p>If required, a subclass can override as many or as few of the
+ * methods as it requires. Each object type (from <code>boolean</code>
+ * to <code>long</code> to <code>Object</code> to <code>int[]</code>) has
+ * its own methods to output it. Most have two versions, detail and summary.
+ *
+ * <p>For example, the detail version of the array based methods will
+ * output the whole array, whereas the summary method will just output
+ * the array length.</p>
+ *
+ * @author Stephen Colebourne
+ * @author Gary Gregory
+ * @author Pete Gieser
+ * @since 1.0
+ * @version $Id: ToStringStyle.java,v 1.32 2004/07/01 17:40:10 ggregory Exp $
+ */
+public abstract class ToStringStyle implements Serializable {
+
+    /**
+     * The default toString style.
+     */
+    public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
+    
+    /**
+     * The multi line toString style.
+     */
+    public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
+    
+    /**
+     * The no field names toString style.
+     */
+    public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();
+    
+    /**
+     * The short prefix toString style.
+     */
+    public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();
+
+    /**
+     * The simple toString style.
+     */
+    public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();
+    
+    /**
+     * Whether to use the field names, the default is <code>true</code>.
+     */
+    private boolean useFieldNames = true;
+    
+    /**
+     * Whether to use the class name, the default is <code>true</code>.
+     */
+    private boolean useClassName = true;
+    
+    /**
+     * Whether to use short class names, the default is <code>false</code>.
+     */
+    private boolean useShortClassName = false;
+    
+    /**
+     * Whether to use the identity hash code, the default is <code>true</code>.
+     */
+    private boolean useIdentityHashCode = true;
+
+    /**
+     * The content start <code>'['</code>.
+     */
+    private String contentStart = "[";
+    
+    /**
+     * The content end <code>']'</code>.
+     */
+    private String contentEnd = "]";
+    
+    /**
+     * The field name value separator <code>'='</code>.
+     */
+    private String fieldNameValueSeparator = "=";
+    
+    /**
+     * Whether the field separator should be added before any other fields.
+     */
+    private boolean fieldSeparatorAtStart = false;
+    
+    /**
+     * Whether the field separator should be added after any other fields.
+     */
+    private boolean fieldSeparatorAtEnd = false;
+    
+    /**
+     * The field separator <code>','</code>.
+     */
+    private String fieldSeparator = ",";
+    
+    /**
+     * The array start <code>'{'</code>.
+     */
+    private String arrayStart = "{";
+    
+    /**
+     * The array separator <code>','</code>.
+     */
+    private String arraySeparator = ",";
+    
+    /**
+     * The detail for array content.
+     */
+    private boolean arrayContentDetail = true;
+    
+    /**
+     * The array end <code>'}'</code>.
+     */
+    private String arrayEnd = "}";
+    
+    /**
+     * The value to use when fullDetail is <code>null</code>,
+     * the default value is <code>true</code>.
+     */
+    private boolean defaultFullDetail = true;
+    
+    /**
+     * The <code>null</code> text <code>'&lt;null&gt;'</code>.
+     */
+    private String nullText = "<null>";
+    
+    /**
+     * The summary size text start <code>'<size'</code>.
+     */
+    private String sizeStartText = "<size=";
+    
+    /**
+     * The summary size text start <code>'&gt;'</code>.
+     */
+    private String sizeEndText = ">";
+    
+    /**
+     * The summary object text start <code>'&lt;'</code>.
+     */
+    private String summaryObjectStartText = "<";
+    
+    /**
+     * The summary object text start <code>'&gt;'</code>.
+     */
+    private String summaryObjectEndText = ">";
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Constructor.</p>
+     */
+    protected ToStringStyle() {
+        super();
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> the superclass toString.</p>
+     * 
+     * <p>A <code>null</code> <code>superToString</code> is ignored.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param superToString  the <code>super.toString()</code>
+     * @since 2.0
+     */
+    public void appendSuper(StringBuffer buffer, String superToString) {
+        appendToString(buffer, superToString);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> another toString.</p>
+     * 
+     * <p>A <code>null</code> <code>toString</code> is ignored.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param toString  the additional <code>toString</code>
+     * @since 2.0
+     */
+    public void appendToString(StringBuffer buffer, String toString) {
+        if (toString != null) {
+            int pos1 = toString.indexOf(contentStart) + contentStart.length();
+            int pos2 = toString.lastIndexOf(contentEnd);
+            if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
+                String data = toString.substring(pos1, pos2);
+                if (fieldSeparatorAtStart) {
+                    removeLastFieldSeparator(buffer);
+                }
+                buffer.append(data);
+                appendFieldSeparator(buffer);
+            }
+        }
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the start of data indicator.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param object  the <code>Object</code> to build a <code>toString</code> for
+     */
+    public void appendStart(StringBuffer buffer, Object object) {
+        if (object != null) {
+            appendClassName(buffer, object);
+            appendIdentityHashCode(buffer, object);
+            appendContentStart(buffer);
+            if (fieldSeparatorAtStart) {
+                appendFieldSeparator(buffer);
+            }
+        }
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the end of data indicator.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param object  the <code>Object</code> to build a
+     *  <code>toString</code> for.
+     */
+    public void appendEnd(StringBuffer buffer, Object object) {
+        if (this.fieldSeparatorAtEnd == false) {
+            removeLastFieldSeparator(buffer);
+        }
+        appendContentEnd(buffer);
+    }
+
+    /**
+     * <p>Remove the last field separator from the buffer.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @since 2.0
+     */
+    protected void removeLastFieldSeparator(StringBuffer buffer) {
+        int len = buffer.length();
+        int sepLen = fieldSeparator.length();
+        if (len > 0 && sepLen > 0 && len >= sepLen) {
+            boolean match = true;
+            for (int i = 0; i < sepLen; i++) {
+                if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
+                    match = false;
+                    break;
+                }
+            }
+            if (match) {
+                buffer.setLength(len - sepLen);
+            }
+        }
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value, printing the full <code>toString</code> of the
+     * <code>Object</code> passed in.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (value == null) {
+            appendNullText(buffer, fieldName);
+
+        } else {
+            appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>,
+     * correctly interpreting its type.</p>
+     *
+     * <p>This method performs the main lookup by Class type to correctly
+     * route arrays, <code>Collections</code>, <code>Maps</code> and
+     * <code>Objects</code> to the appropriate method.</p>
+     *
+     * <p>Either detail or summary views can be specified.</p>
+     *
+     * <p>If a cycle is detected, an object will be appended with the
+     * <code>Object.toString()</code> format.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>,
+     *  not <code>null</code>
+     * @param detail  output detail or not
+     */
+    protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
+        if (ReflectionToStringBuilder.isRegistered(value)
+            && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
+            ObjectUtils.appendIdentityToString(buffer, value);
+
+        } else if (value instanceof Collection) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (Collection) value);
+            } else {
+                appendSummarySize(buffer, fieldName, ((Collection) value).size());
+            }
+
+        } else if (value instanceof Map) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (Map) value);
+            } else {
+                appendSummarySize(buffer, fieldName, ((Map) value).size());
+            }
+
+        } else if (value instanceof long[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (long[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (long[]) value);
+            }
+
+        } else if (value instanceof int[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (int[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (int[]) value);
+            }
+
+        } else if (value instanceof short[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (short[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (short[]) value);
+            }
+
+        } else if (value instanceof byte[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (byte[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (byte[]) value);
+            }
+
+        } else if (value instanceof char[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (char[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (char[]) value);
+            }
+
+        } else if (value instanceof double[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (double[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (double[]) value);
+            }
+
+        } else if (value instanceof float[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (float[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (float[]) value);
+            }
+
+        } else if (value instanceof boolean[]) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (boolean[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (boolean[]) value);
+            }
+
+        } else if (value.getClass().isArray()) {
+            if (detail) {
+                appendDetail(buffer, fieldName, (Object[]) value);
+            } else {
+                appendSummary(buffer, fieldName, (Object[]) value);
+            }
+
+        } else {
+            if (detail) {
+                appendDetail(buffer, fieldName, value);
+            } else {
+                appendSummary(buffer, fieldName, value);
+            }
+        }
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value, printing the full detail of the <code>Object</code>.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
+        buffer.append(value);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>Collection</code>.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param coll  the <code>Collection</code> to add to the
+     *  <code>toString</code>, not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, Collection coll) {
+        buffer.append(coll);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>Map<code>.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param map  the <code>Map</code> to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, Map map) {
+        buffer.append(map);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * value, printing a summary of the <code>Object</code>.</P>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
+        buffer.append(summaryObjectStartText);
+        buffer.append(getShortClassName(value.getClass()));
+        buffer.append(summaryObjectEndText);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, long value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, int value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, short value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, byte value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, char value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, double value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, float value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
+        buffer.append(value);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param value  the value to add to the <code>toString</code>
+     */
+    public void append(StringBuffer buffer, String fieldName, boolean value) {
+        appendFieldStart(buffer, fieldName);
+        appendDetail(buffer, fieldName, value);
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * value.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param value  the value to add to the <code>toString</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
+        buffer.append(value);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>Object</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the toString
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of an
+     * <code>Object</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            Object item = array[i];
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            if (item == null) {
+                appendNullText(buffer, fieldName);
+
+            } else {
+                appendInternal(buffer, fieldName, item, arrayContentDetail);
+            }
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of an array type.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     * @since 2.0
+     */
+    protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
+        buffer.append(arrayStart);
+        int length = Array.getLength(array);
+        for (int i = 0; i < length; i++) {
+            Object item = Array.get(array, i);
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            if (item == null) {
+                appendNullText(buffer, fieldName);
+
+            } else {
+                appendInternal(buffer, fieldName, item, arrayContentDetail);
+            }
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of an
+     * <code>Object</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>long</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>long</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>long</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> an <code>int</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of an
+     * <code>int</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of an
+     * <code>int</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>short</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>short</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>short</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>byte</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>byte</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>byte</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>char</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the <code>toString</code>
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>char</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>char</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>double</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the toString
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>double</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>double</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>float</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the toString
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>float</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>float</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> a <code>boolean</code>
+     * array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     * @param array  the array to add to the toString
+     * @param fullDetail  <code>true</code> for detail, <code>false</code>
+     *  for summary info, <code>null</code> for style decides
+     */
+    public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
+        appendFieldStart(buffer, fieldName);
+
+        if (array == null) {
+            appendNullText(buffer, fieldName);
+
+        } else if (isFullDetail(fullDetail)) {
+            appendDetail(buffer, fieldName, array);
+
+        } else {
+            appendSummary(buffer, fieldName, array);
+        }
+
+        appendFieldEnd(buffer, fieldName);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the detail of a
+     * <code>boolean</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
+        buffer.append(arrayStart);
+        for (int i = 0; i < array.length; i++) {
+            if (i > 0) {
+                buffer.append(arraySeparator);
+            }
+            appendDetail(buffer, fieldName, array[i]);
+        }
+        buffer.append(arrayEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a summary of a
+     * <code>boolean</code> array.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param array  the array to add to the <code>toString</code>,
+     *  not <code>null</code>
+     */
+    protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
+        appendSummarySize(buffer, fieldName, array.length);
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Append to the <code>toString</code> the class name.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param object  the <code>Object</code> whose name to output
+     */
+    protected void appendClassName(StringBuffer buffer, Object object) {
+        if (useClassName && object != null) {
+            if (useShortClassName) {
+                buffer.append(getShortClassName(object.getClass()));
+            } else {
+                buffer.append(object.getClass().getName());
+            }
+        }
+    }
+
+    /**
+     * <p>Append the {@link System#identityHashCode(java.lang.Object)}.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param object  the <code>Object</code> whose id to output
+     */
+    protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
+        if (this.isUseIdentityHashCode() && object!=null) {
+            buffer.append('@');
+            buffer.append(Integer.toHexString(System.identityHashCode(object)));
+        }
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the content start.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     */
+    protected void appendContentStart(StringBuffer buffer) {
+        buffer.append(contentStart);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the content end.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     */
+    protected void appendContentEnd(StringBuffer buffer) {
+        buffer.append(contentEnd);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> an indicator for <code>null</code>.</p>
+     *
+     * <p>The default indicator is <code>'&lt;null&gt;'</code>.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     */
+    protected void appendNullText(StringBuffer buffer, String fieldName) {
+        buffer.append(nullText);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the field separator.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     */
+    protected void appendFieldSeparator(StringBuffer buffer) {
+        buffer.append(fieldSeparator);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> the field start.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name
+     */
+    protected void appendFieldStart(StringBuffer buffer, String fieldName) {
+        if (useFieldNames && fieldName != null) {
+            buffer.append(fieldName);
+            buffer.append(fieldNameValueSeparator);
+        }
+    }
+
+    /**
+     * <p>Append to the <code>toString<code> the field end.</p>
+     * 
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     */
+    protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
+        appendFieldSeparator(buffer);
+    }
+
+    /**
+     * <p>Append to the <code>toString</code> a size summary.</p>
+     *
+     * <p>The size summary is used to summarize the contents of
+     * <code>Collections</code>, <code>Maps</code> and arrays.</p>
+     *
+     * <p>The output consists of a prefix, the passed in size
+     * and a suffix.</p>
+     *
+     * <p>The default format is <code>'&lt;size=n&gt;'<code>.</p>
+     *
+     * @param buffer  the <code>StringBuffer</code> to populate
+     * @param fieldName  the field name, typically not used as already appended
+     * @param size  the size to append
+     */
+    protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
+        buffer.append(sizeStartText);
+        buffer.append(size);
+        buffer.append(sizeEndText);
+    }
+
+    /**
+     * <p>Is this field to be output in full detail.</p>
+     *
+     * <p>This method converts a detail request into a detail level.
+     * The calling code may request full detail (<code>true</code>),
+     * but a subclass might ignore that and always return
+     * <code>false</code>. The calling code may pass in
+     * <code>null</code> indicating that it doesn't care about
+     * the detail level. In this case the default detail level is
+     * used.</p>
+     * 
+     * @param fullDetailRequest  the detail level requested
+     * @return whether full detail is to be shown
+     */
+    protected boolean isFullDetail(Boolean fullDetailRequest) {
+        if (fullDetailRequest == null) {
+            return defaultFullDetail;
+        }
+        return fullDetailRequest.booleanValue();
+    }
+
+    /**
+     * <p>Gets the short class name for a class.</p>
+     *
+     * <p>The short class name is the classname excluding
+     * the package name.</p>
+     *
+     * @param cls  the <code>Class</code> to get the short name of
+     * @return the short name
+     */
+    protected String getShortClassName(Class cls) {
+        return ClassUtils.getShortClassName(cls);
+    }
+
+    // Setters and getters for the customizable parts of the style
+    // These methods are not expected to be overridden, except to make public
+    // (They are not public so that immutable subclasses can be written)
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to use the class name.</p>
+     *
+     * @return the current useClassName flag
+     */
+    protected boolean isUseClassName() {
+        return useClassName;
+    }
+
+    /**
+     * <p>Sets whether to use the class name.</p>
+     *
+     * @param useClassName  the new useClassName flag
+     */
+    protected void setUseClassName(boolean useClassName) {
+        this.useClassName = useClassName;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to output short or long class names.</p>
+     *
+     * @return the current useShortClassName flag
+     * @since 2.0
+     */
+    protected boolean isUseShortClassName() {
+        return useShortClassName;
+    }
+
+    /**
+     * <p>Gets whether to output short or long class names.</p>
+     *
+     * @return the current shortClassName flag
+     * @deprecated Use {@link #isUseShortClassName()}
+     *             Method will be removed in Commons Lang 3.0.
+     */
+    protected boolean isShortClassName() {
+        return useShortClassName;
+    }
+
+    /**
+     * <p>Sets whether to output short or long class names.</p>
+     *
+     * @param useShortClassName  the new useShortClassName flag
+     * @since 2.0
+     */
+    protected void setUseShortClassName(boolean useShortClassName) {
+        this.useShortClassName = useShortClassName;
+    }
+
+    /**
+     * <p>Sets whether to output short or long class names.</p>
+     *
+     * @param shortClassName  the new shortClassName flag
+     * @deprecated Use {@link #setUseShortClassName(boolean)}
+     *             Method will be removed in Commons Lang 3.0.
+     */
+    protected void setShortClassName(boolean shortClassName) {
+        this.useShortClassName = shortClassName;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to use the identity hash code.</p>
+     *
+     * @return the current useIdentityHashCode flag
+     */
+    protected boolean isUseIdentityHashCode() {
+        return useIdentityHashCode;
+    }
+
+    /**
+     * <p>Sets whether to use the identity hash code.</p>
+     *
+     * @param useIdentityHashCode  the new useIdentityHashCode flag
+     */
+    protected void setUseIdentityHashCode(boolean useIdentityHashCode) {
+        this.useIdentityHashCode = useIdentityHashCode;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to use the field names passed in.</p>
+     *
+     * @return the current useFieldNames flag
+     */
+    protected boolean isUseFieldNames() {
+        return useFieldNames;
+    }
+
+    /**
+     * <p>Sets whether to use the field names passed in.</p>
+     *
+     * @param useFieldNames  the new useFieldNames flag
+     */
+    protected void setUseFieldNames(boolean useFieldNames) {
+        this.useFieldNames = useFieldNames;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to use full detail when the caller doesn't
+     * specify.</p>
+     *
+     * @return the current defaultFullDetail flag
+     */
+    protected boolean isDefaultFullDetail() {
+        return defaultFullDetail;
+    }
+
+    /**
+     * <p>Sets whether to use full detail when the caller doesn't
+     * specify.</p>
+     *
+     * @param defaultFullDetail  the new defaultFullDetail flag
+     */
+    protected void setDefaultFullDetail(boolean defaultFullDetail) {
+        this.defaultFullDetail = defaultFullDetail;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether to output array content detail.</p>
+     *
+     * @return the current array content detail setting
+     */
+    protected boolean isArrayContentDetail() {
+        return arrayContentDetail;
+    }
+
+    /**
+     * <p>Sets whether to output array content detail.</p>
+     *
+     * @param arrayContentDetail  the new arrayContentDetail flag
+     */
+    protected void setArrayContentDetail(boolean arrayContentDetail) {
+        this.arrayContentDetail = arrayContentDetail;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the array start text.</p>
+     *
+     * @return the current array start text
+     */
+    protected String getArrayStart() {
+        return arrayStart;
+    }
+
+    /**
+     * <p>Sets the array start text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param arrayStart  the new array start text
+     */
+    protected void setArrayStart(String arrayStart) {
+        if (arrayStart == null) {
+            arrayStart = "";
+        }
+        this.arrayStart = arrayStart;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the array end text.</p>
+     *
+     * @return the current array end text
+     */
+    protected String getArrayEnd() {
+        return arrayEnd;
+    }
+
+    /**
+     * <p>Sets the array end text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param arrayEnd  the new array end text
+     */
+    protected void setArrayEnd(String arrayEnd) {
+        if (arrayStart == null) {
+            arrayStart = "";
+        }
+        this.arrayEnd = arrayEnd;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the array separator text.</p>
+     *
+     * @return the current array separator text
+     */
+    protected String getArraySeparator() {
+        return arraySeparator;
+    }
+
+    /**
+     * <p>Sets the array separator text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param arraySeparator  the new array separator text
+     */
+    protected void setArraySeparator(String arraySeparator) {
+        if (arraySeparator == null) {
+            arraySeparator = "";
+        }
+        this.arraySeparator = arraySeparator;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the content start text.</p>
+     *
+     * @return the current content start text
+     */
+    protected String getContentStart() {
+        return contentStart;
+    }
+
+    /**
+     * <p>Sets the content start text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param contentStart  the new content start text
+     */
+    protected void setContentStart(String contentStart) {
+        if (contentStart == null) {
+            contentStart = "";
+        }
+        this.contentStart = contentStart;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the content end text.</p>
+     *
+     * @return the current content end text
+     */
+    protected String getContentEnd() {
+        return contentEnd;
+    }
+
+    /**
+     * <p>Sets the content end text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param contentEnd  the new content end text
+     */
+    protected void setContentEnd(String contentEnd) {
+        if (contentEnd == null) {
+            contentEnd = "";
+        }
+        this.contentEnd = contentEnd;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the field name value separator text.</p>
+     *
+     * @return the current field name value separator text
+     */
+    protected String getFieldNameValueSeparator() {
+        return fieldNameValueSeparator;
+    }
+
+    /**
+     * <p>Sets the field name value separator text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param fieldNameValueSeparator  the new field name value separator text
+     */
+    protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
+        if (fieldNameValueSeparator == null) {
+            fieldNameValueSeparator = "";
+        }
+        this.fieldNameValueSeparator = fieldNameValueSeparator;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the field separator text.</p>
+     *
+     * @return the current field separator text
+     */
+    protected String getFieldSeparator() {
+        return fieldSeparator;
+    }
+
+    /**
+     * <p>Sets the field separator text.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param fieldSeparator  the new field separator text
+     */
+    protected void setFieldSeparator(String fieldSeparator) {
+        if (fieldSeparator == null) {
+            fieldSeparator = "";
+        }
+        this.fieldSeparator = fieldSeparator;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether the field separator should be added at the start 
+     * of each buffer.</p>
+     * 
+     * @return the fieldSeparatorAtStart flag
+     * @since 2.0
+     */
+    protected boolean isFieldSeparatorAtStart() {
+        return fieldSeparatorAtStart;
+    }
+
+    /**
+     * <p>Sets whether the field separator should be added at the start 
+     * of each buffer.</p>
+     * 
+     * @param fieldSeparatorAtStart  the fieldSeparatorAtStart flag
+     * @since 2.0
+     */
+    protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
+        this.fieldSeparatorAtStart = fieldSeparatorAtStart;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets whether the field separator should be added at the end 
+     * of each buffer.</p>
+     * 
+     * @return fieldSeparatorAtEnd flag
+     * @since 2.0
+     */
+    protected boolean isFieldSeparatorAtEnd() {
+        return fieldSeparatorAtEnd;
+    }
+
+    /**
+     * <p>Sets whether the field separator should be added at the end 
+     * of each buffer.</p>
+     * 
+     * @param fieldSeparatorAtEnd  the fieldSeparatorAtEnd flag
+     * @since 2.0
+     */
+    protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
+        this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the text to output when <code>null</code> found.</p>
+     *
+     * @return the current text to output when null found
+     */
+    protected String getNullText() {
+        return nullText;
+    }
+
+    /**
+     * <p>Sets the text to output when <code>null</code> found.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param nullText  the new text to output when null found
+     */
+    protected void setNullText(String nullText) {
+        if (nullText == null) {
+            nullText = "";
+        }
+        this.nullText = nullText;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the start text to output when a <code>Collection</code>,
+     * <code>Map</code> or array size is output.</p>
+     *
+     * <p>This is output before the size value.</p>
+     *
+     * @return the current start of size text
+     */
+    protected String getSizeStartText() {
+        return sizeStartText;
+    }
+
+    /**
+     * <p>Sets the start text to output when a <code>Collection</code>,
+     * <code>Map</code> or array size is output.</p>
+     *
+     * <p>This is output before the size value.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param sizeStartText  the new start of size text
+     */
+    protected void setSizeStartText(String sizeStartText) {
+        if (sizeStartText == null) {
+            sizeStartText = "";
+        }
+        this.sizeStartText = sizeStartText;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the end text to output when a <code>Collection</code>,
+     * <code>Map</code> or array size is output.</p>
+     *
+     * <p>This is output after the size value.</p>
+     *
+     * @return the current end of size text
+     */
+    protected String getSizeEndText() {
+        return sizeEndText;
+    }
+
+    /**
+     * <p>Sets the end text to output when a <code>Collection</code>,
+     * <code>Map</code> or array size is output.</p>
+     *
+     * <p>This is output after the size value.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param sizeEndText  the new end of size text
+     */
+    protected void setSizeEndText(String sizeEndText) {
+        if (sizeEndText == null) {
+            sizeEndText = "";
+        }
+        this.sizeEndText = sizeEndText;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the start text to output when an <code>Object</code> is
+     * output in summary mode.</p>
+     *
+     * <p>This is output before the size value.</p>
+     *
+     * @return the current start of summary text
+     */
+    protected String getSummaryObjectStartText() {
+        return summaryObjectStartText;
+    }
+
+    /**
+     * <p>Sets the start text to output when an <code>Object</code> is
+     * output in summary mode.</p>
+     *
+     * <p>This is output before the size value.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param summaryObjectStartText  the new start of summary text
+     */
+    protected void setSummaryObjectStartText(String summaryObjectStartText) {
+        if (summaryObjectStartText == null) {
+            summaryObjectStartText = "";
+        }
+        this.summaryObjectStartText = summaryObjectStartText;
+    }
+
+    //---------------------------------------------------------------------
+
+    /**
+     * <p>Gets the end text to output when an <code>Object</code> is
+     * output in summary mode.</p>
+     *
+     * <p>This is output after the size value.</p>
+     *
+     * @return the current end of summary text
+     */
+    protected String getSummaryObjectEndText() {
+        return summaryObjectEndText;
+    }
+
+    /**
+     * <p>Sets the end text to output when an <code>Object</code> is
+     * output in summary mode.</p>
+     *
+     * <p>This is output after the size value.</p>
+     *
+     * <p><code>null</code> is accepted, but will be converted to
+     * an empty String.</p>
+     *
+     * @param summaryObjectEndText  the new end of summary text
+     */
+    protected void setSummaryObjectEndText(String summaryObjectEndText) {
+        if (summaryObjectEndText == null) {
+            summaryObjectEndText = "";
+        }
+        this.summaryObjectEndText = summaryObjectEndText;
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p>Default <code>ToStringStyle</code>.</p>
+     *
+     * <p>This is an inner class rather than using
+     * <code>StandardToStringStyle</code> to ensure its immutability.</p>
+     */
+    private static final class DefaultToStringStyle extends ToStringStyle {
+
+        /**
+         * <p>Constructor.</p>
+         *
+         * <p>Use the static constant rather than instantiating.</p>
+         */
+        private DefaultToStringStyle() {
+            super();
+        }
+
+        /**
+         * <p>Ensure <code>Singleton</code> after serialization.</p>
+         *
+         * @return the singleton
+         */
+        private Object readResolve() {
+            return ToStringStyle.DEFAULT_STYLE;
+        }
+
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p><code>ToStringStyle</code> that does not print out
+     * the field names.</p>
+     *
+     * <p>This is an inner class rather than using
+     * <code>StandardToStringStyle</code> to ensure its immutability.
+     */
+    private static final class NoFieldNameToStringStyle extends ToStringStyle {
+
+        /**
+         * <p>Constructor.</p>
+         *
+         * <p>Use the static constant rather than instantiating.</p>
+         */
+        private NoFieldNameToStringStyle() {
+            super();
+            this.setUseFieldNames(false);
+        }
+
+        /**
+         * <p>Ensure <code>Singleton</code> after serialization.</p>
+         *
+         * @return the singleton
+         */
+        private Object readResolve() {
+            return ToStringStyle.NO_FIELD_NAMES_STYLE;
+        }
+
+    }
+
+    //----------------------------------------------------------------------------
+    
+    /**
+     * <p><code>ToStringStyle</code> that prints out the short
+     * class name and no identity hashcode.</p>
+     *
+     * <p>This is an inner class rather than using
+     * <code>StandardToStringStyle</code> to ensure its immutability.</p>
+     */
+    private static final class ShortPrefixToStringStyle extends ToStringStyle {
+
+        /**
+         * <p>Constructor.</p>
+         *
+         * <p>Use the static constant rather than instantiating.</p>
+         */
+        private ShortPrefixToStringStyle() {
+            super();
+            this.setUseShortClassName(true);
+            this.setUseIdentityHashCode(false);
+        }
+
+        /**
+         * <p>Ensure <code>Singleton</ode> after serialization.</p>
+         * @return the singleton
+         */
+        private Object readResolve() {
+            return ToStringStyle.SHORT_PREFIX_STYLE;
+        }
+
+    }
+
+    /**
+     * <p><code>ToStringStyle</code> that does not print out the
+     * classname, identity hashcode, content start or field name.</p>
+     *
+     * <p>This is an inner class rather than using
+     * <code>StandardToStringStyle</code> to ensure its immutability.</p>
+     */
+    private static final class SimpleToStringStyle extends ToStringStyle {
+
+        /**
+         * <p>Constructor.</p>
+         *
+         * <p>Use the static constant rather than instantiating.</p>
+         */
+        private SimpleToStringStyle() {
+            super();
+            this.setUseClassName(false);
+            this.setUseIdentityHashCode(false);
+            this.setUseFieldNames(false);
+            this.setContentStart("");
+            this.setContentEnd("");
+        }
+
+        /**
+         * <p>Ensure <code>Singleton</ode> after serialization.</p>
+         * @return the singleton
+         */
+        private Object readResolve() {
+            return ToStringStyle.SIMPLE_STYLE;
+        }
+
+    }
+
+    //----------------------------------------------------------------------------
+
+    /**
+     * <p><code>ToStringStyle</code> that outputs on multiple lines.</p>
+     *
+     * <p>This is an inner class rather than using
+     * <code>StandardToStringStyle</code> to ensure its immutability.</p>
+     */
+    private static final class MultiLineToStringStyle extends ToStringStyle {
+
+        /**
+         * <p>Constructor.</p>
+         *
+         * <p>Use the static constant rather than instantiating.</p>
+         */
+        private MultiLineToStringStyle() {
+            super();
+            this.setContentStart("[");
+            this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + "  ");
+            this.setFieldSeparatorAtStart(true);
+            this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
+        }
+
+        /**
+         * <p>Ensure <code>Singleton</code> after serialization.</p>
+         *
+         * @return the singleton
+         */
+        private Object readResolve() {
+            return ToStringStyle.MULTI_LINE_STYLE;
+        }
+
+    }
+
+    //----------------------------------------------------------------------------
+
+// Removed, as the XML style needs more work for escaping characters, arrays,
+// collections, maps and embedded beans.
+//    /**
+//     * ToStringStyle that outputs in XML style
+//     */
+//    private static class XMLToStringStyle extends ToStringStyle {
+//        
+//        /**
+//         * Constructor - use the static constant rather than instantiating.
+//         */
+//        private XMLToStringStyle() {
+//            super();
+//            nullText = "null";
+//            sizeStartText = "size=";
+//            sizeEndText = "";
+//        }
+//        
+//        /**
+//         * @see ToStringStyle#appendStart(StringBuffer, Object)
+//         */
+//        public void appendStart(StringBuffer buffer, Object object) {
+//            buffer.append('<');
+//            buffer.append(getShortClassName(object.getClass()));
+//            buffer.append(" class=\"");
+//            appendClassName(buffer, object);
+//            buffer.append("\" hashCode=\"");
+//            appendIdentityHashCode(buffer, object);
+//            buffer.append("\">");
+//            buffer.append(SystemUtils.LINE_SEPARATOR);
+//            buffer.append("  ");
+//        }
+//
+//        /**
+//         * @see ToStringStyle#appendFieldStart(StringBuffer, String)
+//         */
+//        protected void appendFieldStart(StringBuffer buffer, String fieldName) {
+//            buffer.append('<');
+//            buffer.append(fieldName);
+//            buffer.append('>');
+//        }
+//
+//        /**
+//         * @see ToStringStyle#appendFieldEnd(StringBuffer, String)
+//         */
+//        protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
+//            buffer.append("</");
+//            buffer.append(fieldName);
+//            buffer.append('>');
+//            buffer.append(SystemUtils.LINE_SEPARATOR);
+//            buffer.append("  ");
+//        }
+//
+//        /**
+//         * @see ToStringStyle#appendEnd(StringBuffer, Object)
+//         */
+//        public void appendEnd(StringBuffer buffer, Object object) {
+//            int len = buffer.length();
+//            if (len > 2 && buffer.charAt(len - 1) == ' ' && buffer.charAt(len - 2) == ' ') {
+//                buffer.setLength(len - 2);
+//            }
+//            buffer.append("</");
+//            buffer.append(getShortClassName(object.getClass()));
+//            buffer.append("\">");
+//        }
+//
+//    }
+
+}

Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ValuedEnum.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/ValuedEnum.java	Sat Sep 25 12:11:47 2004
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ldap.common.util;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <p>Abstract superclass for type-safe enums with integer values suitable
+ * for use in <code>switch</code> statements.</p>
+ *
+ * <p><em>NOTE:</em>Due to the way in which Java ClassLoaders work, comparing
+ * <code>Enum</code> objects should always be done using the equals() method,
+ * not <code>==</code>. The equals() method will try <code>==</code> first so
+ * in most cases the effect is the same.</p>
+ *
+ * <p>To use this class, it must be subclassed. For example:</p>
+ *
+ * <pre>
+ * public final class JavaVersionEnum extends ValuedEnum {
+ *   //standard enums for version of JVM
+ *   public static final int  JAVA1_0_VALUE  = 100;
+ *   public static final int  JAVA1_1_VALUE  = 110;
+ *   public static final int  JAVA1_2_VALUE  = 120;
+ *   public static final int  JAVA1_3_VALUE  = 130;
+ *   public static final JavaVersionEnum  JAVA1_0  = new JavaVersionEnum( "Java 1.0", JAVA1_0_VALUE );
+ *   public static final JavaVersionEnum  JAVA1_1  = new JavaVersionEnum( "Java 1.1", JAVA1_1_VALUE );
+ *   public static final JavaVersionEnum  JAVA1_2  = new JavaVersionEnum( "Java 1.2", JAVA1_2_VALUE );
+ *   public static final JavaVersionEnum  JAVA1_3  = new JavaVersionEnum( "Java 1.3", JAVA1_3_VALUE );
+ *
+ *   private JavaVersionEnum(String name, int value) {
+ *     super( name, value );
+ *   }
+ * 
+ *   public static JavaVersionEnum getEnum(String javaVersion) {
+ *     return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
+ *   }
+ * 
+ *   public static JavaVersionEnum getEnum(int javaVersion) {
+ *     return (JavaVersionEnum) getEnum(JavaVersionEnum.class, javaVersion);
+ *   }
+ * 
+ *   public static Map getEnumMap() {
+ *     return getEnumMap(JavaVersionEnum.class);
+ *   }
+ * 
+ *   public static List getEnumList() {
+ *     return getEnumList(JavaVersionEnum.class);
+ *   }
+ * 
+ *   public static Iterator iterator() {
+ *     return iterator(JavaVersionEnum.class);
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>The above class could then be used as follows:</p>
+ *
+ * <pre>
+ * public void doSomething(JavaVersion ver) {
+ *   switch (ver.getValue()) {
+ *     case JAVA1_0_VALUE:
+ *       // ...
+ *       break;
+ *     case JAVA1_1_VALUE:
+ *       // ...
+ *       break;
+ *     //...
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>As shown, each enum has a name and a value. These can be accessed using
+ * <code>getName</code> and <code>getValue</code>.</p>
+ *
+ * <p>The <code>getEnum</code> and <code>iterator</code> methods are recommended.
+ * Unfortunately, Java restrictions require these to be coded as shown in each subclass.
+ * An alternative choice is to use the {@link } class.</p>
+ *
+ * @author Apache Avalon project
+ * @author Stephen Colebourne
+ * @since 1.0
+ * @version $Id: ValuedEnum.java,v 1.16 2004/02/23 04:34:20 ggregory Exp $
+ */
+public abstract class ValuedEnum extends Enum {
+    
+    /** Lang version 1.0.1 serial compatibility */
+    private static final long serialVersionUID = -7129650521543789085L;
+    
+    /**
+     * The value contained in enum.
+     */
+    private final int iValue;
+
+    /**
+     * Constructor for enum item.
+     *
+     * @param name  the name of enum item
+     * @param value  the value of enum item
+     */
+    protected ValuedEnum(String name, int value) {
+        super(name);
+        iValue = value;
+    }
+
+    /**
+     * <p>Gets an <code>Enum</code> object by class and value.</p>
+     *
+     * <p>This method loops through the list of <code>Enum</code>,
+     * thus if there are many <code>Enum</code>s this will be
+     * slow.</p>
+     * 
+     * @param enumClass  the class of the <code>Enum</code> to get
+     * @param value  the value of the <code>Enum</code> to get
+     * @return the enum object, or null if the enum does not exist
+     * @throws IllegalArgumentException if the enum class is <code>null</code>
+     */
+    protected static Enum getEnum(Class enumClass, int value) {
+        if (enumClass == null) {
+            throw new IllegalArgumentException("The Enum Class must not be null");
+        }
+        List list = Enum.getEnumList(enumClass);
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            ValuedEnum enum = (ValuedEnum) it.next();
+            if (enum.getValue() == value) {
+                return enum;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * <p>Get value of enum item.</p>
+     *
+     * @return the enum item's value.
+     */
+    public final int getValue() {
+        return iValue;
+    }
+
+    /**
+     * <p>Tests for order.</p>
+     *
+     * <p>The default ordering is numeric by value, but this
+     * can be overridden by subclasses.</p>
+     * 
+     * @see java.lang.Comparable#compareTo(Object)
+     * @param other  the other object to compare to
+     * @return -ve if this is less than the other object, +ve if greater than,
+     *  <code>0</code> of equal
+     * @throws ClassCastException if other is not an <code>Enum</code>
+     * @throws NullPointerException if other is <code>null</code>
+     */
+    public int compareTo(Object other) {
+        return iValue - ((ValuedEnum) other).iValue;
+    }
+
+    /**
+     * <p>Human readable description of this <code>Enum</code> item.</p>
+     *
+     * @return String in the form <code>type[name=value]</code>, for example:
+     *  <code>JavaVersion[Java 1.0=100]</code>. Note that the package name is
+     *  stripped from the type name.
+     */
+    public String toString() {
+        if (iToString == null) {
+            String shortName = ClassUtils.getShortClassName(getEnumClass());
+            iToString = shortName + "[" + getName() + "=" + getValue() + "]";
+        }
+        return iToString;
+    }
+}